/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  dwmac_hw.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL Eth plugins.
 */
#ifdef __cplusplus
extern "C" {
#endif

#include "dwmac.h"
#include "Mcal_Delay.h"
#include "Mcal_ArchOpt.h"
#include "Eth_Fault.h"
#include "Eth_PBCfg.h"
#include "Eth_Portable.h"
#include "dwmac_common.h"
#include "dwc_ether_qos_wrapper_reg.h"

#define ETH_ROUNDUP(a, b) (((a) + ((b)-1U)) & ~((b)-1U))
#define DWMAC_CRCPOLY     (0xedb88320)

void Eth_update_mmc_status(uint8 CtrlIdx);

// promiscuous or not
enum filter {
    MAC_FILTER_MODE_PROM_ON = 0,
    MAC_FILTER_MODE_PROM_OFF,
    MAC_FILTER_MODE_PROM_NORMAL,
};

#define ETH_START_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_RMII_CLK_OUTPUT_EN      1
#define ETH_RMII_CLK_OUTPUT_DIS     0

#define ETH_STOP_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

#if STD_ON == ETH_UPDATE_FILTER_API
static uint32 ethcrc32table[4][256];
#endif

#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"

#if STD_ON == ETH_UPDATE_FILTER_API

uint32 crc32_calculate(uint32 crc, uint8 const *buf, uint32 len, uint32 (*tab)[256])
{
    const uint32 *b;
    uint32  rem_len;
    const uint32 *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3];
    uint32 q;

    /* Align it */
    if ((long)buf & 3 && len) {
        do {
            crc = t0[(crc ^ ((*buf++))) & 255] ^ (crc >> 8);
        } while ((--len) && ((long)buf) & 3);
    }


    rem_len = len & 3;
    len = len >> 2;

    /*Has been aligned above.*/
    /*PRQA S 3305 1*/
    b = (const uint32 *)buf;

    for (--b; len; --len) {
        q = crc ^ *++b;
        crc = (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
               t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255]);
    }

    len = rem_len;

    if (len) {
        uint8 *p = (uint8 *)(b + 1) - 1;

        do {
            crc = t0[(crc ^ ((*++p))) & 255] ^ (crc >> 8);
        } while (--len);
    }

    return crc;
}

static void crc32init(const uint32 polynomial, uint32 (*tab)[256])
{
    uint32 i, j;
    uint32 crc = 1;

    tab[0][0] = 0;

    for (i = 256 >> 1; i; i >>= 1) {
        crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);

        for (j = 0; j < 256; j += 2 * i)
            tab[0][i + j] = crc ^ tab[0][j];
    }

    for (i = 0; i < 256; i++) {
        crc = tab[0][i];

        for (j = 1; j < 4; j++) {
            crc = tab[0][crc & 0xff] ^ (crc >> 8);
            tab[j][i] = crc;
        }
    }
}

/**
 * @brief Parses a string and converts it to an integer.
 *
 * This function takes a string as input, attempts to convert it to an integer,
 * and returns the result. If the conversion fails, the function returns 0.
 *
 * @param str The input string to be converted.
 * @return The integer representation of the input string, or 0 if the conversion fails.
 */
static uint32 dwmac_crc32(uint32 crc, uint8 const *buf, uint32 len)
{
    return crc32_calculate(crc, buf, len, ethcrc32table);
}
#endif
/**
 * @brief Swap the byte order of a MAC address and store it in a given array.
 *
 * This function takes a 48-bit MAC address represented as two 32-bit integers,
 * `high` and `low`, and rearranges the bytes to match the standard MAC address
 * format. The rearranged address is then stored in the provided `mac` array.
 *
 * @param high   The high 32 bits of the MAC address.
 * @param low    The low 32 bits of the MAC address.
 * @param mac    A 6-element array to store the rearranged MAC address.
 */
static void swap_mac_address(uint32 high, uint32 low, uint8 mac[6])
{
    mac[3] = (uint8)(low & 0xff);
    mac[2] = (uint8)((low >> 8) & 0xff);
    mac[1] = (uint8)((low >> 16) & 0xff);

    mac[0] = (uint8)((low >> 24) & 0xff);
    mac[5] = (uint8)(high & 0xff);
    mac[4] = (uint8)((high >> 8) & 0xff);
}

/**
 * @description: This function selects the Ethernet physical interface type
                 (MII, RMII, or other supported types)
 *               for a given Ethernet controller base address.
 * @param {uint32} RegBase - The base address of the Ethernet controller.
 * @param {uint32} type - The type of physical interface to select
 *                        (e.g., ETH_PHY_INTF_SEL_RMII for RMII).
 */
void select_eth_mii_type(uint32 RegBase, uint32 type)
{
    uint32 value = 0;

    if (type == ETH_PHY_INTF_SEL_RMII) {
        writel(BM_RMII_CLK_OE_CKGEN_RMII_OE, RegBase + RMII_CLK_OE_OFF);
    }

    // Write the selected interface type to the appropriate register.
    value = readl(RegBase + PHY_INTF_SEL_OFF);
    value &= (~FM_PHY_INTF_SEL_SEL);
    value |=  FV_PHY_INTF_SEL_SEL(type);
    writel(value, RegBase + PHY_INTF_SEL_OFF);
}

void dwmac_set_clock_delay(uint32 RegBase, boolean rxDelay, boolean txDelay)
{
    uint32 value = readl(RegBase + PHY_INTF_SEL_OFF);

    if (TRUE == rxDelay) {
        value |= BM_PHY_INTF_SEL_CFG_RXC_DELAY_EN;
    }
    else {
        value &= ~BM_PHY_INTF_SEL_CFG_RXC_DELAY_EN;
    }

    if (TRUE == txDelay) {
        value |= BM_PHY_INTF_SEL_CFG_TXC_DELAY_EN;
    }
    else {
        value &= ~BM_PHY_INTF_SEL_CFG_TXC_DELAY_EN;
    }

    writel(value, RegBase + PHY_INTF_SEL_OFF);
}

/**
 * @brief Sets the MAC address into the specified registers.
 *
 * @param RegBase The base address of the registers, serving as the starting
 *                point for register operations.
 * @param Addr A pointer to the MAC address, which should be a 6-byte array
 *              arranged in standard network byte order.
 * @param high The offset of the high register, used to set the high byte
 *              part of the MAC address.
 * @param low The offset of the low register, used to set the low byte
 *              part of the MAC address.
 *
 * This function splits the 6-byte MAC address and writes it into two registers
 * specified by `RegBase`, `high`, and `low`.
 * The high register stores the last two bytes of the MAC address and may
 * set additional control bits (e.g., MAC_HI_REG_AE).
 * The low register stores the first four bytes of the MAC address.
 */
static void dwmac_set_mac_addr(uint32 RegBase, const uint8* Addr,
                               uint32 high, uint32 low)
{
    uint32 data;

    data = (uint32)((Addr[5] << 8u) | Addr[4]);
#if (STD_ON == ETH_DIRECT_FORWARD_ENABLE)
    /* get config equal to ETH_CFG_CTRL_BCDUP_ENABLE */
    if (TRUE == dwmac_get_packet_dup_enable(RegBase)) {
        data |= MAC_HI_REG_DCS(BIT(0));
    }
#endif
    writel(data | MAC_HI_REG_AE(1U), RegBase + high);
    data = (uint32)((Addr[3] << 24u) | (Addr[2] << 16u) | (Addr[1] << 8u) | Addr[0]);
    writel(data, RegBase + low);
}

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
void dwmac_set_filter_enable(uint32 RegBase, uint32 value)
{
    uint32 data = readl(RegBase + MAC_PACKET_FILTER);
    writel((value | data), RegBase + MAC_PACKET_FILTER);
}

void dwmac_set_packet_dup_enable(uint32 RegBase)
{
    uint32 value = readl(RegBase + MAC_CONFIG_EXI);
    value |= MAC_CONFIG_EXI_PDC;
    writel(value, RegBase + MAC_CONFIG_EXI);
}

boolean dwmac_get_packet_dup_enable(uint32 RegBase)
{
    boolean ret = FALSE;
    uint32 value = readl(RegBase + MAC_CONFIG_EXI);

    if (value & MAC_CONFIG_EXI_PDC) {
        ret = TRUE;
    }
    return ret;
}

void dwmac_set_mac_filter(uint32 RegBase, uint32 macHigh, uint32 macLow,
                          uint32 Reg_n, uint32 DmaChSelect,
                          boolean AddrEnable, boolean SourceAddr)
{
    uint32 data;
    uint8 Addr[6];

    swap_mac_address(macHigh, macLow, Addr);

    data = (uint32)((Addr[5] << 8u) | Addr[4]);
    writel(data | MAC_HI_REG_AE(AddrEnable) | MAC_HI_REG_SA(SourceAddr) | MAC_HI_REG_DCS(DmaChSelect),
            RegBase + MAC_ADDR_HIGH(Reg_n));
    data = (uint32)((Addr[3] << 24u) | (Addr[2] << 16u) | (Addr[1] << 8u) | Addr[0]);
    writel(data, RegBase + MAC_ADDR_LOW(Reg_n));
}

void dwmac_set_vlan_filter(uint32 RegBase, uint16 vlan,
                          uint32 Reg_n, uint32 DmaChSelect)
{
    uint32 data;
    uint32 limit;

    /* 1. write MCA_VLAN_Tag_Data */
    data = (uint32)(MAC_VLAN_TAG_FILTER_VID(vlan) | MAC_VLAN_TAG_FILTER_VEN |
                    MAC_VLAN_TAG_FILTER_ETV | MAC_VLAN_TAG_FILTER_DMACHEN |
                    MAC_VLAN_TAG_FILTER_DMACHN(DmaChSelect));
    writel(data, RegBase + MAC_VLAN_TAG_FILTER);

    /* 2. write MCA_VLAN_Tag_Control OFS */
    data = (uint32)(MAC_VLAN_TAG_CTRL_OFS(Reg_n));
    writel(data, RegBase + MAC_VLAN_TAG_CTRL);

    /* 3. write MCA_VLAN_Tag_Control OB and wait done */
    data |= (uint32)(MAC_VLAN_TAG_CTRL_OB);
    writel(data, RegBase + MAC_VLAN_TAG_CTRL);

    limit = 100;
    while (--limit) {
        data = readl(RegBase + MAC_VLAN_TAG_CTRL);
        if (!(data & MAC_VLAN_TAG_CTRL_OB)){
            break;
        }
        Mcal_udelay(1);
    }
}

void dwmac_set_port_filter(uint32 RegBase, const Eth_PortFilterConfigType* portFilter,
                           uint32 Reg_n, uint32 DmaChSelect)
{
    uint32 data_ctrl = 0;
    uint32 data_addr = 0;

    if (ETH_UDP == portFilter->Protocol) {
        data_ctrl |= (uint32)MAC_L3_L4_CONTROL_L4PEN0;
    }

    if (TRUE == portFilter->SrcPortEn) {
        data_ctrl |= (uint32)MAC_L3_L4_CONTROL_L4SPM0;
        data_addr |= (uint32)MAC_LAYER4_ADDRESS_L4SP0(portFilter->SrcPort);
    }

    if (TRUE == portFilter->DestPortEn) {
        data_ctrl |= (uint32)MAC_L3_L4_CONTROL_L4DPM0;
        data_addr |= (uint32)MAC_LAYER4_ADDRESS_L4DP0(portFilter->DestPort);
    }

    data_ctrl |= (uint32)(MAC_L3_L4_CONTROL_DMCHEN0 |
                          MAC_L3_L4_CONTROL_DMCHN0(DmaChSelect));

    writel(data_ctrl, RegBase + MAC_L3_L4_CONTROL(Reg_n));
    writel(data_addr, RegBase + MAC_LAYER4_ADDRESS(Reg_n));
}
#endif
/**
 * @brief Retrieves the MAC address from the specified registers.
 *
 * @param RegBase The base address of the registers, serving as the starting
 * point for register operations.
 * @param Addr A pointer to a buffer where the MAC address will be stored.
 * The buffer should be at least 6 bytes long.
 * @param high The offset of the high register, used to read the high byte
 * part of the MAC address.
 * @param low The offset of the low register, used to read the low byte
 * part of the MAC address.
 *
 * This function reads the MAC address from two registers specified
 * by `RegBase`, `high`, and `low`.
 * The MAC address is extracted from the high and low words and s
 * tored in the provided buffer `Addr`.
 * The buffer should be capable of holding at least 6 bytes to
 * accommodate the full MAC address.
 */
static void dwmac_get_mac_addr(uint32 RegBase, uint8 *Addr,
                               uint32 high, uint32 low)
{
    uint32 hi_addr, lo_addr;

    /* Read the MAC address from the hardware */
    hi_addr = readl(RegBase + high);
    lo_addr = readl(RegBase + low);

    /* Extract the MAC address from the high and low words */
    Addr[0] = (uint8)(lo_addr & 0xff);
    Addr[1] = (uint8)((lo_addr >> 8) & 0xff);
    Addr[2] = (uint8)((lo_addr >> 16) & 0xff);

    Addr[3] = (uint8)((lo_addr >> 24) & 0xff);
    Addr[4] = (uint8)(hi_addr & 0xff);
    Addr[5] = (uint8)((hi_addr >> 8) & 0xff);
}
/* =====================> MAC BLOCK <==================== */
/**
 * @brief Initializes the MMC (Management and Monitoring Control) module of the DWMAC.
 *
 * @param RegBase The base register address of the DWMAC, used as a starting point for MMC configuration.
 *
 * This function performs the following tasks:
 * 1. Resets the MMC module by writing the MAC_MMC_CTRL_RESET value to the MAC_MMC_CTRL register.
 * 2. Waits until the MMC reset bit is cleared by the hardware or until a timeout occurs.
 * 3. Enables the MMC receive on read by writing MAC_MMC_CTRL_RSTONRD to the MAC_MMC_CTRL register.
 * 4. Disables all MMC overflow interrupts by writing 0xFFFFFFFF to the MAC_MMC_RX_INTR_MASK,
 *    MAC_MMC_TX_INTR_MASK, and MAC_MMC_IPC_INTR_MASK registers.
 *
 * Note: This function assumes that the MAC_MMC_* constants and the writel/readl functions are properly defined.
 */
static void  dwmac_mmc_init(uint32 RegBase)
{
    /* 5us */
    uint32 timeout = 50u,value;
    value = MAC_MMC_CTRL_RESET;
    writel(value, RegBase + MAC_MMC_CTRL);

    /* mac will  cleared  reset bit */
    do {
        value = readl(RegBase + MAC_MMC_CTRL);
        timeout--;
    } while ((value & MAC_MMC_CTRL_RESET) && timeout);

    value = MAC_MMC_CTRL_RSTONRD;
    writel(value, RegBase + MAC_MMC_CTRL);
    /* disable all mmc overflow irq */
    writel(0xFFFFFFFF, RegBase + MAC_MMC_RX_INTR_MASK);
    writel(0xFFFFFFFF, RegBase + MAC_MMC_TX_INTR_MASK);
    writel(0xFFFFFFFF, RegBase + MAC_MMC_IPC_INTR_MASK);
}

static void dwmac5_est_write(uint32 RegBase, uint32 Reg_n, uint32 val, boolean gcl)
{
    uint32 ctrl;
    uint32 limit;
    uint32 data;

    writel(val, RegBase + MTL_EST_GCL_DATA);

    ctrl = (Reg_n << MTL_EST_GCL_ADDR_SHIFT);
    ctrl |= gcl ? 0 : MTL_EST_GCL_GCRR;

    writel(ctrl, RegBase + MTL_EST_GCL_CTRL);

    ctrl |= MTL_EST_GCL_SRWO;
    writel(ctrl, RegBase + MTL_EST_GCL_CTRL);

    limit = 100;
    while (--limit) {
        data = readl(RegBase + MTL_EST_GCL_CTRL);
        if (!(data & MTL_EST_GCL_SRWO)){
            break;
        }
        Mcal_udelay(1);
    }
}

int dwmac5_est_configure(uint32 RegBase, struct stmmac_est *cfg,
                         unsigned int ptp_rate, boolean enable)
{
    int i;
    uint32 ctrl;

    ctrl = readl(RegBase + MTL_EST_CTRL);

    if (TRUE == enable)
    {
        dwmac5_est_write(RegBase, MTL_EST_GCL_BTR_LOW, cfg->btr.nano_seconds, FALSE);
        dwmac5_est_write(RegBase, MTL_EST_GCL_BTR_HIGH, cfg->btr.seconds, FALSE);
        dwmac5_est_write(RegBase, MTL_EST_GCL_TER, cfg->ter, FALSE);
        dwmac5_est_write(RegBase, MTL_EST_GCL_LLR, cfg->gcl_size, FALSE);
        dwmac5_est_write(RegBase, MTL_EST_GCL_CTR_LOW, cfg->ctr.nano_seconds, FALSE);
        dwmac5_est_write(RegBase, MTL_EST_GCL_CTR_HIGH, cfg->ctr.seconds, FALSE);

        for (i = 0; i < cfg->gcl_size; i++) {
            dwmac5_est_write(RegBase, i, cfg->gcl[i], TRUE);
        }

        ctrl &= ~MTL_EST_PTOV;
        ctrl |= ((1000000000 / ptp_rate) * 6) << MTL_EST_PTOV_SHIFT;
        ctrl |= MTL_EST_EEST | MTL_EST_SSWL;
    }
    else
    {
        ctrl &= ~MTL_EST_EEST;
    }

    writel(ctrl, RegBase + MTL_EST_CTRL);

    return 0;
}

/**
 * @name:
 * @Desc:
 * @param {void } *RegBase
 * @param {uint32} MTU
 * @param {uint32} Speed
 * @return {*}
 */
void dwmac_core_init(uint32 RegBase, uint32 MTU, uint32 mac_high, uint32 mac_low, uint32 Speed)
{
    uint8 mac[6];

    uint32 value = readl(RegBase + MAC_CONFIG);
    value |= MAC_CORE_INIT;
    value &= ~MAC_CONFIG_TE;
    value &= ~MAC_CONFIG_RE;
#if defined(ENABLE_QOS_LOOPBACK)
    value |= MAC_CONFIG_LM;
#endif /** #if defined(ENABLE_QOS_LOOPBACK) */

    if (MTU > 1500)
        value |= MAC_CONFIG_2K;

    if (MTU > 2000)
        value |= MAC_CONFIG_JE;
    /* default enable 1000 */
    value &= ~(MAC_CONFIG_FES | MAC_CONFIG_PS);
    if (PHY_SPEED_100 == Speed) {
        value |= MAC_CONFIG_FES | MAC_CONFIG_PS;
    }
    if(PHY_SPEED_10 == Speed){
        value |= MAC_CONFIG_PS;
    }

    writel(value, RegBase + MAC_CONFIG);
    /* Disable All MAC interrupts */
    value = 0;
    writel(value, RegBase + MAC_INT_EN);
#if defined(CFG_ETH_DIS_CRC)
    value = readl(RegBase + MAC_CONFIG_EXI);
    value |= 0x1 << 16;
    writel(value, RegBase + MAC_CONFIG_EXI);
#endif
#if defined(MAX_POWER_CASE)
    /* enable correctable error  */
    value = readl(RegBase + MTL_ECC_INT_EN);
    value |= MTL_ECC_COR_ERR_EST | MTL_ECC_COR_ERR_RX | MTL_ECC_COR_ERR_TX;
    writel(value, RegBase + MTL_ECC_INT_EN);
#endif

    /* enable ecc */
    value = readl(RegBase + MTL_ECC_CTRL);
    value |= MTL_ECC_DEFAULT_ENABLE;
    writel(value, RegBase + MTL_ECC_CTRL);
    /* enable bus parity */
    value = readl(RegBase + MTL_DPP_CTRL);
    value |= MTL_DPP_CTRL_DATA_PARITY | MTL_DPP_CTRL_SLAVE_PARITY;
    writel(value, RegBase + MTL_DPP_CTRL);

    /* Init MMC  */
    dwmac_mmc_init(RegBase);
    swap_mac_address(mac_high, mac_low, mac);
    dwmac_set_umac_addr(RegBase, mac, 0);

    value = 0;
    value |= MAC_PACKET_FILTER_PM;

    writel(value, RegBase + MAC_PACKET_FILTER);

    /* Does not receive any multicasts by default */
    writel(0x0, RegBase + MAC_HASH_TAB_0_31);
    writel(0x0, RegBase + MAC_HASH_TAB_32_63);
    writel(0x0, RegBase + MAC_HASH_TAB_64_95);
    writel(0x0, RegBase + MAC_HASH_TAB_96_127);
    value = readl(RegBase + MAC_PACKET_FILTER);
    value &= ~MAC_PACKET_FILTER_PM;
    /*
        The  DAIF bit will applcable unicast and multcast
        so only supports imperfect filtering for multcast.
    */
    value |= MAC_PACKET_FILTER_HMC;
    writel(value, RegBase + MAC_PACKET_FILTER);
#if STD_ON == ETH_UPDATE_FILTER_API
    /* Does not receive any multicasts by default end */
    crc32init(DWMAC_CRCPOLY, ethcrc32table);
#endif
}
/**
 * @name:
 * @Desc:
 * @param {void} *Addr
 * @param {uint8} Mode
 * @param {uint32} Queue
 * @return {*}
 */
void dwmac_mac_rx_queue_mcbc_routing(uint32  RegBase, uint8 Channel)
{
    uint32 value;
    value = readl(RegBase + MAC_RXQ_CTRL1);
    value |= MAC_RXQCTRL_MCBCQEN;
    value &= ~MAC_RXQCTRL_MCBCQ_MASK;
    value |= (Channel << MAC_RXQCTRL_MCBCQ_SHIFT & MAC_RXQCTRL_MCBCQ_MASK);
    writel(value, RegBase + MAC_RXQ_CTRL1);
}
#if defined(ETH_DEBUG_ENABLE)
/**
 * @name:
 * @Desc:
 * @param {void*} Addr
 * @return {*}
 */
void dwmac_dump_mac(uint32  Addr)
{
    uint32 RegBase = Addr;
    int i;

    for (i = 0; i < MAC_REG_NUM; i++)
        DBG("MAC:%p = %p\n", i * 4, readl(RegBase + i * 4));
}
#endif
/**
 * @description: This function sets the MAC address for the specified Ethernet controller.
 * @param RegBase: The base register address of the Ethernet controller.
 * @param Addr: Pointer to the MAC address to be set.
 * @param Reg_n: The register number associated with the MAC address to be set.
 */
void dwmac_set_umac_addr(uint32 RegBase,
                         const uint8 *Addr, uint32 Reg_n)
{
    dwmac_set_mac_addr(RegBase, Addr, MAC_ADDR_HIGH(Reg_n), MAC_ADDR_LOW(Reg_n));
}
/**
 * @name:
 * @Desc:
 * @param {*}
 * @return {*}
 */
void dwmac_get_umac_addr(uint32 RegBase,
                         unsigned char *Addr, uint32 Reg_n)
{

    dwmac_get_mac_addr(RegBase, Addr, MAC_ADDR_HIGH(Reg_n),
                       MAC_ADDR_LOW(Reg_n));
}
#if STD_ON == ETH_UPDATE_FILTER_API
/**
 * @function: is_quirks_mac_addr
 * @description: This function checks the given MAC address for specific quirks
 * and determines the corresponding filter mode.
 * @param Addr: A pointer to the MAC address to be checked.
 * @return: An enum filter value indicating the filter mode
 * (MAC_FILTER_MODE_PROM_ON, MAC_FILTER_MODE_PROM_OFF, or MAC_FILTER_MODE_PROM_NORMAL).
 */
static enum filter is_quirks_mac_addr(const uint8 *Addr)
{
    uint8 i = 0, mode = 0x07u;

    for (i = 0; i < 6u; i++) {
        if (Addr[i] != (uint8)0xFFu)
            mode &= (uint8)0xFEu;

        if (Addr[i] != (uint8)0x0u)
            mode &= (uint8)0xFDu;
    }

    if (mode & (uint8)0x01u)
        return MAC_FILTER_MODE_PROM_ON;
    else if (mode & (uint8)0x02u) {
        return MAC_FILTER_MODE_PROM_OFF;
    } else {
        return MAC_FILTER_MODE_PROM_NORMAL;
    }
}

/**
 * @brief Sets the MAC filter for the specified Ethernet controller.
 *
 * This function configures the MAC filter based on the provided mode and MAC address.
 * It handles both promiscuous mode and hash table filtering.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Mode An enum value indicating the operation mode (e.g., add to filter or remove from filter).
 * @param Addr Pointer to the MAC address to be added to or removed from the filter.
 *
 * @return A signed integer indicating the success or failure of the operation.
 *         0 indicates success, -1 indicates failure.
 */
sint32 dwmac_set_filter(uint32 RegBase, uint32 Mode, const uint8 *Addr)
{
    sint32 ret = -1;
    enum filter quirk_mode = is_quirks_mac_addr(Addr);
    uint32 bit_nr, value = 0, hash_table_width, valid_bits = 5u;

    if (MAC_FILTER_MODE_PROM_NORMAL != quirk_mode) {
        value = readl(RegBase + MAC_PACKET_FILTER);

        if (MAC_FILTER_MODE_PROM_ON == quirk_mode) {
            value |= MAC_PACKET_FILTER_PA | MAC_PACKET_FILTER_PR;

        } else {
            value &= ~(MAC_PACKET_FILTER_PA | MAC_PACKET_FILTER_PR);
        }

        writel(value, RegBase + MAC_PACKET_FILTER);
        ret = 0;
    }
    else
    {
        value = readl(RegBase + MAC_HW_FEATURE1);
        value &= MAC_HASH_TABLE_WIDTH_MASK;
        hash_table_width = value >> MAC_HASH_TABLE_WIDTH_SHIFT;

        if (MAC_HASH_TABLE_WIDTH_64 == hash_table_width) {
            valid_bits = 5u;
            ret = 0;
        } else if (MAC_HASH_TABLE_WIDTH_128 == hash_table_width) {
            valid_bits = 6u;
            ret = 0;
        }/*else is not need */

        if (0 == ret) {
            bit_nr = Mcal_Arch_rbitu32((uint32)(~dwmac_crc32(0xFFFFFFFF, Addr, valid_bits))) >> (31u - valid_bits);

            if (Mode == (uint32)ETH_ADD_TO_FILTER) {
                /* add to fillter,not fillter out */
                value = readl(RegBase + MAC_HASH_TAB_0_31 + HASH_TABLE_IDX(bit_nr));
                value |= HASH_REG_MASK(bit_nr  & 0x1fu);
            } else {
                value = readl(RegBase + MAC_HASH_TAB_0_31 + HASH_TABLE_IDX(bit_nr));
                value &= (uint32)(~HASH_REG_MASK(bit_nr  & 0x1fu));
            }

            writel(value, RegBase + MAC_HASH_TAB_0_31 + HASH_TABLE_IDX(bit_nr));
        }
    }

    return ret;
}
#endif
#if defined(ETH_DEBUG_ENABLE)
/**
 * @name:
 * @Desc:
 * @param {void } *RegBase
 * @param {uint32} Queue
 * @return {*}
 */
void dwmac_dump_mtl(uint32 RegBase, uint32 Queue)
{
    uint32 base = 0xc00;

    for (int i = 0; i <= 0x13c; i += 4) {
        DBG("Reg=%p,Val=%p\n", base + i, readl(RegBase + base + i));
    }
}
#endif

/**
 * @brief Configures the addend value for the Precision Time Protocol (PTP)
 * in the Ethernet controller.
 *
 * This function sets the addend value in the PTP timestamping system and issues
 * a command to update it.
 * It then waits for the update to complete.
 *
 * @param regbase The base register address of the Ethernet controller.
 * @param addend The new addend value to be configured.
 *
 * @note This function assumes that the necessary constants
 *      (e.g., MAC_PTP_TSAR, MAC_PTP_CONTRL, PTP_CONTRL_TSADDREG)
 *       are defined and available for use. It also relies on external
 *      functions like `writel`, `readl`, `EthFaultInj_Eth_Ptp_Test`,
 *       and `Mcal_udelay` for register access and delay functionality.
 */
static void config_addend(uint32 regbase, uint32 addend)
{
    uint32 value;
    uint32 limit;

    writel(addend, regbase + MAC_PTP_TSAR);
    /* issue command to update the addend value */
    value = readl(regbase + MAC_PTP_CONTRL);
    value |= PTP_CONTRL_TSADDREG;
    writel(value, regbase + MAC_PTP_CONTRL);

    /* wait for present addend update to complete */
    limit = 1000;

    while (--limit) {
        value = readl(regbase + MAC_PTP_CONTRL);
        EthFaultInj_Eth_Ptp_Test();
        if (!(value & PTP_CONTRL_TSADDREG)){
            break;
        }
        Mcal_udelay(1);
    }
}

/**
 * @brief Configures the sub-second increment and addend values for Precision Time Protocol (PTP) in the Ethernet controller.
 *
 * This function calculates the sub-second increment value based on the PTP clock frequency and writes it to the
 * appropriate register. It also calculates and configures the addend value required for accurate timestamping.
 *
 * @param regbase The base register address of the Ethernet controller.
 * @param ptp_clock The PTP clock frequency in Hertz (Hz).
 *
 * @note This function assumes that the necessary constants (e.g., MAC_PTP_CONTRL, PTP_CONTRL_TSCFUPDT, PTP_SSIR_SSINC_SHIFT)
 *       are defined and available for use. It also relies on the `config_addend` function to configure the addend value.
 *       The calculation of the addend is based on the sub-second increment value and the PTP clock frequency.
 */
void config_sub_second_increment(uint32 regbase, uint32 ptp_clock)
{
    uint32 value = readl(regbase + MAC_PTP_CONTRL);
    uint64 data;
    uint32 reg_value;

    data = (1000000000ULL / ptp_clock);

    if (value & PTP_CONTRL_TSCFUPDT)
        data *= 2;

    data &= 0xFF;

    reg_value = (uint32)data;

    reg_value <<= PTP_SSIR_SSINC_SHIFT;

    writel(reg_value, regbase + MAC_PTP_SSINC);

    uint64 temp = 1000000000ULL / data;

    /* calculate default added value:
     * formula is :
     * addend = (2^32)/freq_div_ratio;
     * where, freq_div_ratio = 1e9ns/sec_inc
     */
    temp = (uint64)(temp << 32);
    temp = temp / ptp_clock;
    config_addend(regbase, (uint32)temp);

}

/**
 * @brief Initializes the system time for Precision Time Protocol (PTP) in the Ethernet controller.
 *
 * This function configures the PTP control register to enable timestamping, timestamp fine update,
 * and timestamp control software reset. It then writes the seconds and nanoseconds values to the
 * PTP registers and issues a command to initialize the system time. It waits for the initialization
 * to complete before returning.
 *
 * @param regbase The base register address of the Ethernet controller.
 * @param sec The seconds value to set for the PTP system time.
 * @param nsec The nanoseconds value to set for the PTP system time, masked to ensure it falls within the valid range.
 *
 * @note This function assumes that the necessary constants (e.g., MAC_PTP_CONTRL, PTP_CONTRL_TSEN, PTP_CONTRL_TSCFUPDT,
 *       PTP_CONTRL_TSCTRLSSR, PTP_NSEC_MASKE, PTP_CONTRL_INIT) are defined and available for use. It also relies on
 *       external functions `readl`, `writel`, `EthFaultInj_Eth_Ptp_Test`, and `Mcal_udelay` for register access,
 *       delay functionality, and fault injection testing.
 */
void dwmac_init_systime(uint32 regbase, uint32 sec, uint32 nsec)
{
    uint32 value, limit;

    // Read the PTP control register and enable timestamping, timestamp fine update, and timestamp control software reset
    value = readl(regbase + MAC_PTP_CONTRL);
    value |= PTP_CONTRL_TSEN | PTP_CONTRL_TSCFUPDT | PTP_CONTRL_TSCTRLSSR;
    writel(value, regbase + MAC_PTP_CONTRL);

    // Write the seconds value to the PTP seconds register
    writel(sec, regbase + MAC_PTP_SEC);

    // Mask the nanoseconds value to ensure it falls within the valid range and write it to the PTP nanoseconds register
    nsec &= PTP_NSEC_MASKE;
    writel(nsec, regbase + MAC_PTP_NSEC);

    /* issue command to initialize the system time value */
    value = readl(regbase + MAC_PTP_CONTRL);
    value |= PTP_CONTRL_INIT;
    writel(value, regbase + MAC_PTP_CONTRL);

    // Set a limit for waiting for the system time initialization to complete
    limit = 1000u;

    /* wait for present system time initialize to complete */
    while (--limit) {
        // Read the PTP control register
        value = readl(regbase + MAC_PTP_CONTRL);

        // Call a function to perform an optional fault injection test (note: this function is not defined in the provided code snippet)
        EthFaultInj_Eth_Ptp_Test();

        // Check if the INIT bit in the PTP control register is cleared, indicating that initialization is complete
        if (!(value & PTP_CONTRL_INIT)){
            break;
        }

        // Delay for a microsecond to prevent excessive busy-waiting
        Mcal_udelay(1);
    }
}

/**
 * @brief Retrieves the current system time for Precision Time Protocol (PTP) from the Ethernet controller.
 *
 * This function reads the seconds and nanoseconds values from the PTP registers, ensuring that they are
 * consistent by retrying if a rollover occurs during the read operation. It stores the retrieved values
 * in the provided pointers.
 *
 * @param regbase The base register address of the Ethernet controller.
 * @param sec A pointer to where the seconds value of the PTP system time will be stored.
 * @param nsec A pointer to where the nanoseconds value of the PTP system time will be stored.
 *
 * @note This function assumes that the necessary constants (e.g., MAC_PTP_SEC, MAC_PTP_NSEC) are defined
 *       and available for use. It also relies on the `readl` function for register access.
 *
 * @return None. The function updates the values pointed to by `sec` and `nsec` with the retrieved system time.
 */
void dwmac_get_time(uint32 regbase, uint32 *sec, uint32 *nsec)
{
    /* twice is enough 10 for margin,is 1us max */
    uint32 timeout = 10;
    uint32 ns, sec0, sec1;

    /* Get the TSS value */
    sec1 = readl(regbase + MAC_PTP_SEC);
    do {
        sec0 = sec1;
        /* Get the TSSS value */
        ns = readl(regbase + MAC_PTP_NSEC);
        /* Get the TSS value */
        sec1 = readl(regbase + MAC_PTP_SEC);
        timeout--;
    } while ((sec0 != sec1) && timeout);

    *sec = sec0;
    *nsec = ns;
}

/**
 * @brief Configures the timestamp filter for Precision Time Protocol (PTP) packets in the Ethernet controller.
 *
 * This function sets up the PTP control register to enable timestamping for specific PTP packets based on
 * the PTP version, master/slave role, and the desired receive filter configuration.
 *
 * @param regbase The base register address of the Ethernet controller.
 * @param ptp_v The PTP version to configure the timestamp filter for (PTP_V1 or PTP_V2).
 * @param is_ptp_master Indicates whether the device is configured as a PTP master or slave.
 * @param rxfilter Specifies the receive filter configuration for PTP packets.
 *
 * @note This function assumes that the necessary constants (e.g., MAC_PTP_CONTRL, PTP_CONTRL_TSENALL,
 *       PTP_CONTRL_TSIPV4ENA, PTP_CONTRL_TSIPV6ENA, PTP_CONTRL_TSIPENA, PTP_CONTRL_TSVER2ENA,
 *       PTP_CONTRL_TSMSTRENA, PTP_CONTRL_TSEVNTENA, PTP_CONTRL_SNAPTYPSEL_1) and enum types
 *       (ptp_version_t, ptp_mode_t, ptp_rx_filter_t) are defined and available for use. It also relies on
 *       the `readl` and `writel` functions for register access.
 *
 * @return None. The function modifies the PTP control register directly to configure the timestamp filter.
 */
void setup_timestamp_filter(uint32 regbase, ptp_version_t ptp_v,
                            ptp_mode_t is_ptp_master, ptp_rx_filter_t rxfilter)
{
    /* 802.AS1, any layer */
    uint32 systime_flags = readl(regbase + MAC_PTP_CONTRL);

    if (rxfilter == ALL_RX_PACKET) {
        /* time stamp any incoming packet */
        systime_flags |= PTP_CONTRL_TSENALL;
    } else {
        systime_flags |= PTP_CONTRL_TSIPV4ENA | PTP_CONTRL_TSIPV6ENA | PTP_CONTRL_TSIPENA;

        /* default is PTP v1 */
        if (ptp_v == PTP_V2) {
            /* PTP v2 */
            systime_flags |= PTP_CONTRL_TSVER2ENA;
        }

        /* The snapshot is taken only for the messages that are relevant to the master/slave node.  */
        if (rxfilter != ALL_RX_PTP_PACKET) {
            if (PTP_MASTER == is_ptp_master) {
                /* master role take time stamp for Delay_Req messages only */
                systime_flags |= PTP_CONTRL_TSMSTRENA | PTP_CONTRL_TSEVNTENA;
            } else {
                /* slave role take time stamp for SYNC messages only */
                systime_flags |= PTP_CONTRL_TSEVNTENA;
            }
        } else {
            /* take time stamp for all event messages */
            systime_flags |= PTP_CONTRL_SNAPTYPSEL_1;
        }
    }

    writel(systime_flags, regbase + MAC_PTP_CONTRL);
}
/**
 * @brief Stops the transmission of frames on the Ethernet controller.
 *
 * This function disables the transmission of frames by clearing the Transmit
 * Enable (TE) bit in the MAC configuration register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 *
 * @note This function assumes that the necessary constants (e.g., MAC_CONFIG,
 *       MAC_CONFIG_TE) and the `readl` and `writel`
 *       functions for register access are defined and available for use.
 *
 * @return None. The function modifies the MAC configuration register directly
 * to stop transmission.
 */
void dwmac_mac_stop_tx(uint32 RegBase)
{
    uint32 value = readl(RegBase + MAC_CONFIG);
    value &= ~MAC_CONFIG_TE;
    writel(value, RegBase + MAC_CONFIG);
}

/**
 * @brief Starts the transmission of frames on the Ethernet controller.
 *
 * This function enables the transmission of frames by setting the Transmit
 * Enable (TE) bit in the MAC configuration register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 *
 * @note This function assumes that the necessary constants (e.g., MAC_CONFIG,
 *       MAC_CONFIG_TE) and the `readl` and `writel`
 *       functions for register access are defined and available for use.
 *
 * @return None. The function modifies the MAC configuration register directly
 * to start transmission.
 */
void dwmac_mac_start_tx(uint32 RegBase)
{
    uint32 value = readl(RegBase + MAC_CONFIG);
    value |= MAC_CONFIG_TE;
    writel(value, RegBase + MAC_CONFIG);
}
/* =====================>MAC BLOCK END<==================== */
/* =====================>  MTL BLOCK  <==================== */
/**
 * @name:
 * @Desc:
 * @param {void} *RegBase
 * @param {uint32} alg
 * @return {*}
 */
// Function to program the MTL RX algorithms
void dwmac_prog_mtl_rx_algorithms(uint32  RegBase, uint32 Algorithm)
{
    // Read the current value of the MTL_OP_MODE register
    uint32 value = readl(RegBase + MTL_OP_MODE);
    // If the Algorithm is set to SP, clear the MTL_OP_RAA bit
    if(MTL_RX_ALGORITHM_SP == Algorithm)
        value &= ~MTL_OP_RAA;
    // Otherwise, set the MTL_OP_RAA_WSP bit
    else
        value |= MTL_OP_RAA_WSP;

    // Write the new value back to the MTL_OP_MODE register
    writel(value, RegBase + MTL_OP_MODE);
}
/**
 * @name:
 * @Desc:
 * @param {void} *RegBase
 * @param {uint32} alg
 * @return {*}
 */
void dwmac_prog_mtl_tx_algorithms(uint32  RegBase, uint32 Algorithm)
{
    // Read the current value of the MTL_OP_MODE register
    uint32 value = readl(RegBase + MTL_OP_MODE);

    // Clear the current algorithm bits
    value &= ~MTL_OP_SCHALG_MASK;
    // defaule is wrr
    // If the algorithm is WFQ, set the corresponding bit
    if(MTL_TX_ALGORITHM_WFQ == Algorithm){
        value |= MTL_OP_SCHALG_WFQ;
    // If the algorithm is DWRR, set the corresponding bit
    }else if(MTL_TX_ALGORITHM_DWRR == Algorithm){
        value |= MTL_OP_SCHALG_DWRR;
    // If the algorithm is SP, set the corresponding bit
    }else if(MTL_TX_ALGORITHM_SP == Algorithm){
        value |= MTL_OP_SCHALG_SP;
    }
    /* flush MTL  */
    // Set the flush bit
    value |= 0x01u << 9u;
    // Write the new value to the MTL_OP_MODE register
    writel(value, RegBase + MTL_OP_MODE);
}
/**
 * @name:
 * @Desc:
 * @param {void} *RegBase
 * @param {uint32} alg
 * @return {*}
 */
//This function returns the quantum weight of a given algorithm and absolute rate
static uint32 mtl_tx_algorithms_quantum_weight_get(uint32 Algorithm,uint32 abs_rate)
{
    //Calculate the result by dividing the absolute rate by 10
    uint32 result = abs_rate;

    //If the algorithm is WFQ, multiply the result by the WFQ max value
    if(Algorithm == MTL_TX_ALGORITHM_WFQ)
    {
        result *= MTL_ALGORITHM_WFQ_BASE;
    }
    //If the algorithm is DWRR, multiply the result by the DWRR max value
    else if(Algorithm == MTL_TX_ALGORITHM_DWRR)
    {
#if !defined(ETH_INTERNAL_TEST_ONLY)
        result *= MTL_ALGORITHM_DWRR_BASE;
#endif /** #if !defined(ETH_INTERNAL_TEST_ONLY) */
    }
    //Otherwise, multiply the result by the WRR max value
    else
    {
#if !defined(ETH_INTERNAL_TEST_ONLY)
        result *= MTL_ALGORITHM_WRR_BASE;
#endif /** #if !defined(ETH_INTERNAL_TEST_ONLY) */
    }
    //Return the result, or 1 if the result is less than or equal to 0
    return result<=0?1:result;
}
/**
 * @name:
 * @Desc:
 * @param {void} *Addr
 * @param {uint32} Queue
 * @param {uint32} Channel
 * @return {*}
 */
// Function to map MTL DMA
void dwmac_map_mtl_dma(uint32  Addr, uint32 Queue, uint32 Channel)
{
    // Set the base address of the register
    uint32 RegBase = Addr;
    uint32 value;

    // Check if the queue is less than 4
    if (Queue < 4u) {
        // Read the value of the register
        value = readl(RegBase + MTL_RXQ_DMA_MAP0);
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
        value |= MTL_RXQ_DMA_Q04DDMACH(Queue);
#endif
    }
    else {
        // Read the value of the register
        value = readl(RegBase + MTL_RXQ_DMA_MAP1);
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
        value |= MTL_RXQ_DMA_QXDDMACH(Queue);
#endif
    }

    // Check if the queue is 0 or 4
    if (0u == Queue || 4u == Queue) {
        // Clear the mask of the register
        value &= (uint32)(~MTL_RXQ_DMA_Q0MDMACH_MASK);
        // Set the channel of the register
        value |= (uint32)MTL_RXQ_DMA_Q0MDMACH(Channel);
    } else {
        // Clear the mask of the register
        value &= (uint32)(~MTL_RXQ_DMA_QXMDMACH_MASK(Queue));
        // Set the channel of the register
        value |= (uint32)MTL_RXQ_DMA_QXMDMACH(Channel, Queue);
    }

    // Check if the queue is less than 4
    if (Queue < 4u)
        // Write the value to the register
        writel(value, RegBase + MTL_RXQ_DMA_MAP0);
    else
        // Write the value to the register
        writel(value, RegBase + MTL_RXQ_DMA_MAP1);
}
/**
 * @name:
 * @Desc:
 * @param {void} *Addr
 * @param {uint8} Mode
 * @param {uint32} Queue
 * @return {*}
 */
// Function to enable a receive queue
void dwmac_rx_queue_enable(uint32  Addr, uint32 Mode, uint32 Queue)
{
    // Set the base address of the register
    uint32  RegBase = Addr;
    // Read the current value of the register
    uint32 value = readl(RegBase + MAC_RXQ_CTRL0);

    // Clear the specified queue
    value &= (uint32)MAC_RX_QUEUE_CLEAR(Queue);

    // If the mode is AVB, enable the AVB queue
    if (Mode == MTL_QUEUE_MODE_AVB)
        value |= (uint32)MAC_RX_AV_QUEUE_ENABLE(Queue);
    // If the mode is DCB, enable the DCB queue
    else if (Mode == MTL_QUEUE_MODE_DCB)
        value |= (uint32)MAC_RX_DCB_QUEUE_ENABLE(Queue);

    // Write the new value to the register
    writel(value, RegBase + MAC_RXQ_CTRL0);
}
/**
 * @brief Configures the receive operation mode and interrupt control for
 * a DMA receive channel.
 *
 * This function sets up the receive operation mode register
 * (MTL_QUEUE_RX_OP_MODE) for a specified DMA receive channel,
 * enabling features such as forwarding undersized good packets,
 * setting the receive queue size, and enabling flow control
 * based on the FIFO size and queue mode. It also configures
 * the receive interrupt control register (MTL_QUEUE_INT_CTRL)
 * to enable receive overflow interrupts.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA receive channel number to configure.
 * @param FifoSize The size of the FIFO allocated to the receive channel, in bytes.
 * @param QMode The queue mode for the receive channel
 *              e.g., MTL_QUEUE_MODE_AVB for Audio Video Bridging).
 *
 * @note This function assumes that the necessary constants
 *      (e.g., MTL_QUEUE_RX_OP_MODE, MTL_RXQ_OP_MODE_FUP, MTL_RXQ_OP_MODE_RSF,
 *       MTL_RXQ_OP_MODE_RQS_MASK, MTL_RXQ_OP_MODE_RQS_SHIFT, MTL_RXQ_OP_MODE_EHFC,
 *      MTL_RXQ_OP_MODE_RFD_MASK, MTL_RXQ_OP_MODE_RFD_SHIFT,
 *       MTL_RXQ_OP_MODE_RFA_MASK, MTL_RXQ_OP_MODE_RFA_SHIFT, MTL_QUEUE_INT_CTRL,
 *      MTL_Q_INT_CTRL_RXOIE) and the `readl` and `writel`
 *       functions for register access are defined and available for use.
 *      It also calls an external function
 *       `EthFaultInj_Eth_Qsize_Test()` for optional fault injection
 *      testing, which is not defined in the provided
 *       code snippet. The behavior of the function may vary depending
 *      on the defined macros (e.g., E3650).
 *
 * @return None. The function modifies the receive operation mode and
 * interrupt control registers directly.
 */
void dwmac_dma_rx_chan_op_mode(uint32 RegBase, uint32 Channel,
                               int FifoSize, uint32 QMode)
{
    uint32 rfd, rfa;
    uint32 rqs = (uint32)((FifoSize / 256) - 1);
    uint32 mtl_rx_op, mtl_rx_int;

    mtl_rx_op = readl(RegBase + MTL_QUEUE_RX_OP_MODE(Channel));
    /* Forward Undersized Good Packets */
    mtl_rx_op |= MTL_RXQ_OP_MODE_FUP;

    mtl_rx_op |= MTL_RXQ_OP_MODE_RSF;

    mtl_rx_op &= ~MTL_RXQ_OP_MODE_RQS_MASK;
    mtl_rx_op |= rqs << MTL_RXQ_OP_MODE_RQS_SHIFT;

    /* Enable flow control only if each Channel gets 4 KiB or more FIFO and
     * only if Channel is not an AVB Channel.
     */
    if ((FifoSize >= 4096) && (QMode != MTL_QUEUE_MODE_AVB)) {


        mtl_rx_op |= MTL_RXQ_OP_MODE_EHFC;

        /* Set Threshold for Activating Flow Control to min 2 frames,
         * i.e. 1500 * 2 = 3000 bytes.
         *
         * Set Threshold for Deactivating Flow Control to min 1 frame,
         * i.e. 1500 bytes.
         */
        EthFaultInj_Eth_Qsize_Test();
        if (4096 == FifoSize)
        {
            /* This violates the above formula because of FIFO size
             * limit therefore overflow may occur in spite of this.
             */
            rfd = ETH_RFD_NUM_QSIZE_4096; /* Full-2.5K */
            rfa = ETH_RFA_NUM_QSIZE_4096; /* Full-1.5K */
        }
        else
        {
            /* 6K */
            rfd = ETH_RFD_NUM_QSIZE_6144; /* Full-4K */
            rfa = ETH_RFA_NUM_QSIZE_6144; /* Full-2K */
        }

        // Clear the RFD bits in the mtl_rx_op register
        mtl_rx_op &= ~MTL_RXQ_OP_MODE_RFD_MASK;
        // Set the RFD bits in the mtl_rx_op register
        mtl_rx_op |= rfd << MTL_RXQ_OP_MODE_RFD_SHIFT;

        // Clear the RFA bits in the mtl_rx_op register
        mtl_rx_op &= ~MTL_RXQ_OP_MODE_RFA_MASK;
        // Set the RFA bits in the mtl_rx_op register
        mtl_rx_op |= rfa << MTL_RXQ_OP_MODE_RFA_SHIFT;
    }

    writel(mtl_rx_op, RegBase + MTL_QUEUE_RX_OP_MODE(Channel));

    /* Enable MTL RX overflow */
    mtl_rx_int = readl(RegBase + MTL_QUEUE_INT_CTRL(Channel));
    writel(mtl_rx_int | MTL_Q_INT_CTRL_RXOIE,
           RegBase + MTL_QUEUE_INT_CTRL(Channel));
}
/*
    Mode  transmit store and forward enable or not
    QMode transmit Queue enable or not
    fifo  transmit Queue size
*/
void dwmac_dma_tx_chan_op_mode(uint32 RegBase, uint32 Channel,
                               uint32 FifoSize, uint32 QMode)
{
    uint32 tqs;
    uint32 mtl_tx_op = readl(RegBase + MTL_QUEUE_TX_OP_MODE(Channel));

    tqs = (FifoSize >> 8u) - 1u;

    /* Transmit COE type 2 cannot be done in cut-through Mode. */
    mtl_tx_op |= MTL_TXQ_OP_MODE_TSF;

    /* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
     * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
     * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
     * with reset values: TXQEN off, TQS 256 bytes.
     *
     * TXQEN must be written for multi-Channel operation and TQS must
     * reflect the available fifo size per Queue (total fifo size / number
     * of enabled queues).
     */
    // Clear the TXQEN bit in the mtl_tx_op register
    mtl_tx_op &= ~MTL_TXQ_OP_MODE_TXQEN_MASK;

    // If the QMode is not AVB, set the TXQEN bit in the mtl_tx_op register
    if (QMode != MTL_QUEUE_MODE_AVB)
        mtl_tx_op |= MTL_TXQ_OP_MODE_TXQEN;
    // Otherwise, set the TXQEN_AV bit in the mtl_tx_op register
    else
        mtl_tx_op |= MTL_TXQ_OP_MODE_TXQEN_AV;

    // Clear the TQS bit in the mtl_tx_op register
    mtl_tx_op &= ~MTL_TXQ_OP_MODE_TQS_MASK;
    // Set the TQS bit in the mtl_tx_op register with the value of tqs
    mtl_tx_op |= tqs << MTL_TXQ_OP_MODE_TQS_SHIFT;

    // Write the mtl_tx_op register to the specified register base address
    writel(mtl_tx_op, RegBase +  MTL_QUEUE_TX_OP_MODE(Channel));
}
/*
    set queue weight.
*/
/**
 * @brief Sets the transmit weight for a DMA transmit channel based on the specified algorithm.
 *
 * This function configures the transmit weight for a specified DMA transmit channel using the provided weight value
 * and algorithm. The transmit weight affects the priority and bandwidth allocation for the channel in the MTL (Media
 * Transmission Layer). The function first calculates the true weight value based on the algorithm and the provided
 * weight, then sets the transmit weight register (MTL_QUEUE_TX_WEIGHT) for the specified channel. Additionally, if the
 * channel is not the first one, it disables the credit-based congestion control and average algorithm selection bits
 * in the estimation control register (MTL_QUEUE_EST_CTRL).
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Algorithms The transmit algorithm selection. This parameter determines how the weight value is interpreted.
 * @param Channel The DMA transmit channel number to configure.
 * @param weight The initial weight value for the transmit channel. The actual weight value used may be modified based
 *               on the selected algorithm.
 *
 * @note This function assumes that the necessary constants (e.g., MTL_QUEUE_EST_CTRL, MTL_TXQ_ETS_CTRL_CC, MTL_TXQ_ETS_CTRL_AVALG,
 *       MTL_QUEUE_TX_WEIGHT, MTL_TXQ_QT_WEIGHT_ISCQW_MASK) and the `readl` and `writel` functions for register access are
 *       defined and available for use. It also relies on an external function `mtl_tx_algorithms_quantum_weight_get()`
 *       to calculate the true weight value based on the algorithm and provided weight, which is not defined in the
 *       provided code snippet.
 *
 * @return None. The function modifies the transmit weight and estimation control registers directly.
 */
void dwmac_mtl_tx_chan_set_weight(uint32 RegBase,uint32 Algorithms ,uint32 Channel, uint32 weight)
{
    uint32 value,true_weght;
    true_weght = mtl_tx_algorithms_quantum_weight_get(Algorithms,weight);

    if (Channel != 0) {
        value = readl(RegBase + MTL_QUEUE_EST_CTRL(Channel));
        value &= ~(MTL_TXQ_ETS_CTRL_CC | MTL_TXQ_ETS_CTRL_AVALG);
        writel(value, RegBase +  MTL_QUEUE_EST_CTRL(Channel));
    }

    value = readl(RegBase + MTL_QUEUE_TX_WEIGHT(Channel));
    value &= ~MTL_TXQ_QT_WEIGHT_ISCQW_MASK;
    value |= true_weght & MTL_TXQ_QT_WEIGHT_ISCQW_MASK;
    writel(value, RegBase +  MTL_QUEUE_TX_WEIGHT(Channel));

}

/*
    config abv  queue cbs credit.
    isc: idleSlope
    ssc: sendSlope
    hc:  hiCredit
    lc:  loCredit
*/
void dwmac_mtl_tx_chan_set_cbs(uint32 RegBase, uint32 Channel,
                               uint32 isc, uint32 ssc, uint32 hc, uint32 lc)
{
    // Read the current value of the channel's TX weight register
    uint32 value = readl(RegBase + MTL_QUEUE_TX_WEIGHT(Channel));
    // Clear the ISCQW bits
    value &= ~MTL_TXQ_QT_WEIGHT_ISCQW_MASK;
    // Set the ISCQW bits with the new value
    value |= isc & MTL_TXQ_QT_WEIGHT_ISCQW_MASK;
    // Write the new value back to the register
    writel(value, RegBase +  MTL_QUEUE_TX_WEIGHT(Channel));

    // Read the current value of the channel's TX sleep credit register
    value = readl(RegBase + MTL_QUEUE_TX_SSC(Channel));
    // Clear the SSC bits
    value &= ~MTL_TXQ_SEND_SLP_CRED_SSC_MASK;
    // Set the SSC bits with the new value
    value |= ssc & MTL_TXQ_SEND_SLP_CRED_SSC_MASK;
    // Write the new value back to the register
    writel(value, RegBase +  MTL_QUEUE_TX_SSC(Channel));

    // Read the current value of the channel's TX high credit register
    value = readl(RegBase + MTL_QUEUE_TX_HC(Channel));
    // Clear the HC bits
    value &= ~MTL_TXQ_HIGH_CRED_HC_MASK;
    // Set the HC bits with the new value
    value |= hc & MTL_TXQ_HIGH_CRED_HC_MASK;
    // Write the new value back to the register
    writel(value, RegBase +  MTL_QUEUE_TX_HC(Channel));

    // Read the current value of the channel's TX low credit register
    value = readl(RegBase + MTL_QUEUE_TX_LC(Channel));
    // Clear the LC bits
    value &= ~MTL_TXQ_LOW_CRED_LC_MASK;
    // Set the LC bits with the new value
    value |= lc & MTL_TXQ_LOW_CRED_LC_MASK;
    // Write the new value back to the register
    writel(value, RegBase +  MTL_QUEUE_TX_LC(Channel));
    /* enable  */
    value = readl(RegBase + MTL_QUEUE_EST_CTRL(Channel));
    // Set the CC and AVALG bits
    value |= MTL_TXQ_ETS_CTRL_CC | MTL_TXQ_ETS_CTRL_AVALG;
    // Write the new value back to the register
    writel(value, RegBase +  MTL_QUEUE_EST_CTRL(Channel));
}

/**
 * @brief Configures a DMA transmit channel for Strict Priority (SP) mode.
 *
 * This function sets up a specified DMA transmit channel to
 * operate in Strict Priority (SP) mode. In SP mode,
 * transmit frames are scheduled based on their priority levels,
 * with higher priority frames being transmitted
 * before lower priority frames. The function disables credit-based
 * congestion control and average algorithm
 * selection in the estimation control register (MTL_QUEUE_EST_CTRL)
 * for the specified channel. Additionally,
 * it configures the transmit queue priority mapping registers
 * (MAC_TXQ_PRTY_MAP0 and MAC_TXQ_PRTY_MAP1) to
 * associate priority levels with the transmit queue.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA transmit channel number to configure for SP mode.
 *
 * @note This function assumes that the necessary constants
 *       (e.g., MTL_TXQ_ETS_CTRL_CC, MTL_TXQ_ETS_CTRL_AVALG,
 *       MTL_QUEUE_EST_CTRL, MAC_TXQ_PRTY_MAP0, MAC_TXQ_PRTY_MAP1)
 *       and the `readl` and `writel` functions for
 *       register access are defined and available for use.
 *       The specific priority mapping (0x03020100 and
 *       0x07060504) is hardcoded in this function and may need
 *       to be adjusted based on the desired priority
 *       handling.
 *
 * @return None. The function modifies the estimation control
 *         and transmit queue priority mapping registers
 *         directly.
 */
void dwmac_mtl_tx_chan_set_sp_mode(uint32 RegBase, uint32 Channel)
{
    /* config est of this mtl queue  */
    uint32 value = readl(RegBase + MTL_QUEUE_EST_CTRL(Channel));
    value &= ~(MTL_TXQ_ETS_CTRL_CC | MTL_TXQ_ETS_CTRL_AVALG);
    writel(value, RegBase +  MTL_QUEUE_EST_CTRL(Channel));
    /* map priorities */
    writel(0x03020100, RegBase + MAC_TXQ_PRTY_MAP0);
    writel(0x07060504, RegBase + MAC_TXQ_PRTY_MAP1);
}
/* =====================>MTL BLOCK END<==================== */
/* =====================>  DMA BLOCK  <==================== */
/**
 * @brief Resets the DMA (Direct Memory Access) engine of the Ethernet controller.
 *
 * This function initiates a software reset of the DMA engine by
 * setting the software reset bit in the DMA bus mode
 * register. It then waits for the reset to complete by polling
 * the reset bit until it is cleared. If the reset does
 * not complete within a specified timeout limit, the function
 * returns an error code. Optionally, if the `ETH_DISABLE_IRQ_PULSE`
 * macro is defined, it also configures the DMA bus mode register
 * to use level-sensitive interrupts instead of pulse-triggered
 * interrupts.
 *
 * @param RegBase The base register address of the Ethernet controller's DMA engine.
 *
 * @return 0 on success, indicating that the DMA reset completed
 *         successfully within the specified timeout limit.
 *         Returns -1 on failure, indicating that the DMA reset
 *         did not complete within the specified timeout limit.
 *
 * @note This function assumes that the necessary constants
 *       (e.g., DMA_MODE, DMA_BUS_MODE_SFT_RESET,
 *       DMA_MODE_INTM_MASK, DMA_MODE_INTM_LEVEL) and the
 *       `readl`, `writel`, and `Mcal_udelay` functions for register
 *       access and delay are defined and available for use.
 *       The `ETH_DISABLE_IRQ_PULSE` macro controls the
 *       optional interrupt mode configuration.
 */
sint32 dwmac_dma_reset(uint32 RegBase)
{
    uint32 limit;
    uint32 value = readl(RegBase + DMA_MODE);

    /* DMA SW reset */
    value |= DMA_BUS_MODE_SFT_RESET;
    writel(value, RegBase + DMA_MODE);
    limit = 100000;

    while (--limit) {
        if (!(readl(RegBase + DMA_MODE) & DMA_BUS_MODE_SFT_RESET))
            break;

        Mcal_udelay(1);
    }

    if (0u == limit) {
        return -1;
    }
#if defined(ETH_DISABLE_IRQ_PULSE)
    value = readl(RegBase + DMA_MODE);
    value &= ~DMA_MODE_INTM_MASK;
    value |= DMA_MODE_INTM_LEVEL;
    writel(value, RegBase + DMA_MODE);
#endif
    return 0;
}

/**
 * @brief Sets the tail pointer for the receive descriptor ring of a DMA channel.
 *
 * This function updates the tail pointer register of a specified DMA channel to point to the last receive
 * descriptor in the receive descriptor ring. This is used to indicate the end of the ring and to manage the
 * flow of receive descriptors during the DMA transfer process.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param tail_ptr The address of the last receive descriptor in the ring.
 * @param Channel The DMA channel number for which to set the tail pointer.
 *
 * @note This function assumes that the `DMA_CH_RX_END_ADDR` macro is defined and provides the correct offset
 *       for accessing the tail pointer register of the specified DMA channel. Additionally, it relies on the
 *       `writel` function for writing to the register.
 *
 * @return None. This function does not return a value.
 */
void dwmac_set_rx_tail_ptr(uint32 RegBase, uint32  tail_ptr, uint32 Channel)
{
    writel(tail_ptr, RegBase + DMA_CH_RX_END_ADDR(Channel));
}

/**
 * @brief Sets the tail pointer for the transmit descriptor ring of a DMA channel.
 *
 * This function updates the tail pointer register of a specified DMA channel to
 * point to the last transmit
 * descriptor in the transmit descriptor ring. This is used to indicate the
 * end of the ring and to manage the
 * flow of transmit descriptors during the DMA transfer process.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param tail_ptr The address of the last transmit descriptor in the ring.
 * @param Channel The DMA channel number for which to set the tail pointer.
 *
 * @note This function assumes that the `DMA_CH_TX_END_ADDR` macro is defined
 *      and provides the correct offset
 *       for accessing the tail pointer register of the specified DMA channel.
 *      Additionally, it relies on the
 *       `writel` function for writing to the register.
 *
 * @return None. This function does not return a value.
 */
void dwmac_set_tx_tail_ptr(uint32 RegBase, uint32  tail_ptr, uint32 Channel)
{
    writel(tail_ptr, RegBase + DMA_CH_TX_END_ADDR(Channel));
}

/**
 * @brief Triggers the reception of new data packets for a DMA channel.
 *
 * This function manually triggers the DMA engine to start processing new
 * receive descriptors for the specified
 * DMA channel. It accomplishes this by reading and immediately writing
 * back the tail pointer register, which
 * effectively notifies the DMA engine that there are new descriptors
 * available for processing.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to trigger reception.
 *
 * @note This function assumes that the `DMA_CH_RX_END_ADDR` macro is
 *       defined and provides the correct offset
 *       for accessing the tail pointer register of the specified DMA
 *       channel. Additionally, it relies on the
 *       `readl` and `writel` functions for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_rx_trigger(uint32 RegBase, uint32 Channel)
{
    uint32 tail = readl(RegBase + DMA_CH_RX_END_ADDR(Channel));
    writel(tail, RegBase + DMA_CH_RX_END_ADDR(Channel));
}

/**
 * @brief Starts DMA transmission for a specified channel.
 *
 * This function initiates DMA transmission for the specified channel by enabling the transmission state
 * (DMA_CH_TX_CTRL_ST) in the DMA channel's control register. Additionally, it also enables the transmission
 * enable (MAC_CONFIG_TE) bit in the MAC configuration register to ensure that the MAC layer is ready to
 * transmit packets.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to start transmission.
 *
 * @note This function assumes that the `DMA_CH_TX_CONTROL` and `MAC_CONFIG` macros are defined and provide
 *       the correct offsets for accessing the DMA channel's control register and the MAC configuration register,
 *       respectively. Additionally, it relies on the `readl` and `writel` functions for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_start_tx(uint32 RegBase, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_TX_CONTROL(Channel));

    value |= DMA_CH_TX_CTRL_ST;
    writel(value, RegBase + DMA_CH_TX_CONTROL(Channel));
    value = readl(RegBase + MAC_CONFIG);
    value |= MAC_CONFIG_TE;
    writel(value, RegBase + MAC_CONFIG);
}

/**
 * @brief Stops DMA transmission for a specified channel.
 *
 * This function halts DMA transmission for the specified channel by disabling the transmission state
 * (DMA_CH_TX_CTRL_ST) in the DMA channel's control register. Additionally, it also disables the transmission
 * enable (MAC_CONFIG_TE) bit in the MAC configuration register to prevent the MAC layer from transmitting
 * packets.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to stop transmission.
 *
 * @note This function assumes that the `DMA_CH_TX_CONTROL` and `MAC_CONFIG` macros are defined and provide
 *       the correct offsets for accessing the DMA channel's control register and the MAC configuration register,
 *       respectively. Additionally, it relies on the `readl` and `writel` functions for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_stop_tx(uint32 RegBase, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_TX_CONTROL(Channel));

    value &= ~DMA_CH_TX_CTRL_ST;
    writel(value, RegBase + DMA_CH_TX_CONTROL(Channel));
    value = readl(RegBase + MAC_CONFIG);
    value &= ~MAC_CONFIG_TE;
    writel(value, RegBase + MAC_CONFIG);
}

/**
 * @brief Starts DMA reception for a specified channel.
 *
 * This function initiates DMA reception for the specified channel by enabling the reception state
 * (DMA_CH_RX_CTRL_SR) in the DMA channel's control register. Additionally, it also enables the reception
 * enable (MAC_CONFIG_RE) bit in the MAC configuration register to ensure that the MAC layer is ready to
 * receive packets.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to start reception.
 *
 * @note This function assumes that the `DMA_CH_RX_CONTROL` and `MAC_CONFIG` macros are defined and provide
 *       the correct offsets for accessing the DMA channel's control register and the MAC configuration register,
 *       respectively. Additionally, it relies on the `readl` and `writel` functions for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_start_rx(uint32 RegBase, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_RX_CONTROL(Channel));

    value |= DMA_CH_RX_CTRL_SR;

    writel(value, RegBase + DMA_CH_RX_CONTROL(Channel));
    value = readl(RegBase + MAC_CONFIG);
    value |= MAC_CONFIG_RE;
    writel(value, RegBase + MAC_CONFIG);
}

/**
 * @brief Stops DMA reception for a specified channel.
 *
 * This function halts DMA reception for the specified channel by disabling the reception state
 * (DMA_CH_RX_CTRL_SR) in the DMA channel's control register. Additionally, it also disables the reception
 * enable (MAC_CONFIG_RE) bit in the MAC configuration register to prevent the MAC layer from receiving
 * packets.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to stop reception.
 *
 * @note This function assumes that the `DMA_CH_RX_CONTROL` and `MAC_CONFIG` macros are defined and provide
 *       the correct offsets for accessing the DMA channel's control register and the MAC configuration register,
 *       respectively. Additionally, it relies on the `readl` and `writel` functions for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_stop_rx(uint32 RegBase, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_RX_CONTROL(Channel));

    value &= ~DMA_CH_RX_CTRL_SR;
    writel(value, RegBase + DMA_CH_RX_CONTROL(Channel));
    value = readl(RegBase + MAC_CONFIG);
    value &= ~MAC_CONFIG_RE;
    writel(value, RegBase + MAC_CONFIG);
}

/**
 * @brief Sets the transmit ring length for a specified DMA channel.
 *
 * This function configures the transmit ring length for the specified DMA channel by writing the desired
 * length value to the DMA channel's transmit ring length register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param len The desired transmit ring length.
 * @param Channel The DMA channel number for which to set the transmit ring length.
 *
 * @note This function assumes that the `DMA_CH_TX_RING_LEN` macro is defined and provides the correct offset
 *       for accessing the transmit ring length register of the specified DMA channel. Additionally, it relies
 *       on the `writel` function for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_set_tx_ring_len(uint32 RegBase, uint32 len, uint32 Channel)
{
    writel(len, RegBase + DMA_CH_TX_RING_LEN(Channel));
}

/**
 * @brief Sets the receive ring length for a specified DMA channel.
 *
 * This function configures the receive ring length for the specified DMA channel by writing the desired
 * length value to the DMA channel's receive ring length register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param len The desired receive ring length.
 * @param Channel The DMA channel number for which to set the receive ring length.
 *
 * @note This function assumes that the `DMA_CH_RX_RING_LEN` macro is defined and provides the correct offset
 *       for accessing the receive ring length register of the specified DMA channel. Additionally, it relies
 *       on the `writel` function for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_set_rx_ring_len(uint32 RegBase, uint32 len, uint32 Channel)
{
    writel(len, RegBase + DMA_CH_RX_RING_LEN(Channel));
}

/**
 * @brief Enables or disables DMA interrupts for a specified channel.
 *
 * This function configures the DMA interrupt enable mask for the specified channel to enable or disable
 * receive and transmit interrupts as per the provided parameters. It first clears any pending interrupts
 * in the DMA channel's status register before setting the interrupt enable mask.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to configure interrupts.
 * @param rx A boolean indicating whether to enable receive interrupts. True to enable, false to disable.
 * @param tx A boolean indicating whether to enable transmit interrupts. True to enable, false to disable.
 *
 * @note This function assumes that the `DMA_CH_INTR_DEFAULT_MASK`, `DMA_CH_STATUS`, `DMA_CH_INTR_ENA`,
 *       `DMA_CH_INTR_EN_RIE`, `DMA_CH_INTR_EN_RBUE`, and `DMA_CH_INTR_EN_TIE` macros are defined and
 *       provide the correct offsets and masks for accessing the DMA channel's interrupt enable register,
 *       status register, and specific interrupt enable bits. Additionally, it relies on the `writel` function
 *       for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_enable_dma_irq(uint32 RegBase, uint32 Channel, boolean rx, boolean tx)
{
    uint32 irq_enable_mask = DMA_CH_INTR_DEFAULT_MASK;
    /* clearn irq */
    writel(0x3fffc7, RegBase + DMA_CH_STATUS(Channel));

    /* enable irq */
    if (!rx) {
        irq_enable_mask &= ~DMA_CH_INTR_EN_RIE;
        irq_enable_mask &= ~DMA_CH_INTR_EN_RBUE;
    }

    if (!tx) {
        irq_enable_mask &= ~DMA_CH_INTR_EN_TIE;
    }

    writel(irq_enable_mask, RegBase + DMA_CH_INTR_ENA(Channel));
}

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
/**
 * @brief Disables DMA interrupts for a specified channel rx or tx.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to disable interrupts.
 * @param rx  True for rx, false for tx.
 *
 * @return None. This function does not return a value.
 */
void dwmac_disable_specify_dma_irq(uint32 RegBase, uint32 Channel, boolean rx)
{
    uint32 irq_enable = readl(RegBase + DMA_CH_INTR_ENA(Channel));;
    /* clearn irq */
    writel(0x3fffc7, RegBase + DMA_CH_STATUS(Channel));

    /* enable irq */
    if (TRUE == rx) {
        /* rx */
        irq_enable &= ~DMA_CH_INTR_EN_RIE;
        irq_enable &= ~DMA_CH_INTR_EN_RBUE;
    }
    else {
        /* tx */
        irq_enable &= ~DMA_CH_INTR_EN_TIE;
    }

    writel(irq_enable, RegBase + DMA_CH_INTR_ENA(Channel));
}
#endif

/**
 * @brief Disables all interrupts for a specified DMA channel and related MTL channel.
 *
 * This function disables all interrupts for the specified DMA channel by writing 0 to the DMA channel's
 * interrupt enable register. Additionally, it disables interrupts for the related MTL channel (if applicable)
 * by writing 0 to the MTL channel's interrupt control register. If the specified DMA channel is 0, it also
 * disables ECC interrupts for the entire MTL block by writing 0 to the MTL ECC interrupt enable register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number for which to disable interrupts.
 *
 * @note This function assumes that the `DMA_CH_INTR_ENA`, `MTL_QUEUE_INT_CTRL`, and `MTL_ECC_INT_EN` macros
 *       are defined and provide the correct offsets for accessing the DMA channel's interrupt enable register,
 *       the MTL channel's interrupt control register, and the MTL ECC interrupt enable register, respectively.
 *       Additionally, it relies on the `writel` function for register access.
 *
 * @return None. This function does not return a value.
 */
void dwmac_disable_all_irqs(uint32 RegBase, uint32 Channel)
{
    writel(0, RegBase + DMA_CH_INTR_ENA(Channel));
    writel(0, RegBase + MTL_QUEUE_INT_CTRL(Channel));
    if(0 == Channel)
        writel(0,RegBase + MTL_ECC_INT_EN);
}

/**
 * @brief Initializes the receive DMA channel with a specified base address and packet buffer length.
 *
 * This function initializes the receive DMA channel by configuring the packet buffer length and base address
 * for the specified channel. It clears the packet buffer length field in the DMA channel's receive control
 * register, sets a new packet buffer length (16 in this case), and writes the provided base address to the
 * DMA channel's receive base address register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param base_ptr The base address of the receive descriptor ring for the specified DMA channel.
 * @param Channel The DMA channel number to initialize.
 *
 * @note This function assumes that the `DMA_CH_RX_CONTROL`, `DMA_CH_RX_BASE_ADDR`, `DMA_CH_TX_CTRL_PBL_MASK`,
 *       `DMA_CH_TX_CTRL_RPBL_SHIFT`, and `writel` macro/function are defined and provide the correct offsets,
 *       masks, and functionality for accessing and modifying the DMA channel's registers.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_init_rx_chan(uint32 RegBase, uint32  base_ptr, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_RX_CONTROL(Channel));
    value &= ~DMA_CH_TX_CTRL_PBL_MASK;
    value = value | (16u << DMA_CH_TX_CTRL_RPBL_SHIFT);
    writel(value, RegBase + DMA_CH_RX_CONTROL(Channel));

    writel(base_ptr, RegBase + DMA_CH_RX_BASE_ADDR(Channel));
}

/**
 * @brief Initializes the transmit DMA channel for optimal performance.
 *
 * This function initializes the transmit DMA channel by configuring the packet buffer length and enabling
 * optimal store and forward mode for best performance. It clears the packet buffer length field in the DMA
 * channel's transmit control register, sets the packet buffer length to 16 (or adjusts based on the specific
 * hardware's SDRAM access characteristics), and enables the optimal store and forward mode. Finally, it
 * writes the provided base address of the transmit descriptor ring to the DMA channel's transmit base
 * address register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param base_ptr The base address of the transmit descriptor ring for the specified DMA channel.
 * @param Channel The DMA channel number to initialize.
 *
 * @note For the e3 chip, when the data buffers are placed in SDRAM, the maximum transmit burst length is
 *       set to 16 or less to comply with the hardware's access characteristics. If the buffers are placed
 *       in IRAM, the burst length is unlimited. The `DMA_CH_TX_CTRL_PBL_MASK`, `DMA_CH_CTRL_PBL_SHIFT`,
 *       `DMA_CH_TX_CTRL_OSP`, `DMA_CH_TX_CONTROL`, `DMA_CH_TX_BASE_ADDR`, and `writel` macro/function are
 *       assumed to be defined and provide the correct offsets, masks, constants, and functionality for
 *       accessing and modifying the DMA channel's registers.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_init_tx_chan(uint32 RegBase, uint32  base_ptr, uint32 Channel)
{
    uint32 value;

    value = readl(RegBase + DMA_CH_TX_CONTROL(Channel));
    /*
        In e3 chip when data buff place in sdram set max tx burst
        length less than or equal 16锟斤拷Unlimited if on IRAM.
     */
    value &= ~DMA_CH_TX_CTRL_PBL_MASK;
    value = value | (16u << DMA_CH_CTRL_PBL_SHIFT);

    /* Enable OSP to get best performance */
    value |= DMA_CH_TX_CTRL_OSP;

    writel(value, RegBase + DMA_CH_TX_CONTROL(Channel));
    writel(base_ptr, RegBase + DMA_CH_TX_BASE_ADDR(Channel));
}

/**
 * @brief Initializes the DMA channel's control register with specified skip length.
 *
 * This function initializes the DMA channel's control register by configuring the packet buffer length
 * field (although it's noted that the actual buffer length is not explicitly set in this function) and
 * setting the descriptor skip length. The descriptor skip length specifies the number of descriptors to
 * skip before the next descriptor is fetched for transmission or reception.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number to initialize.
 * @param skip The number of descriptors to skip in the descriptor ring.
 *
 * @note The packet buffer length field is cleared in this function, but no specific buffer length is set.
 *       The `DMA_CH_CONTROL`, `DMA_CH_CTRL_PBL`, `DMA_CH_CTRL_DSL_SHIFT`, `DMA_CH_CTRL_DSL_MASK`, and
 *       `writel` macro/function are assumed to be defined and provide the correct offsets, masks, constants,
 *       and functionality for accessing and modifying the DMA channel's registers. The actual packet buffer
 *       length should be set separately, if needed, by modifying the relevant register field.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_init_channel(uint32 RegBase,uint32 Channel, uint32 skip)
{
    uint32 value;

    /* common Channel control register config */
    value = readl(RegBase + DMA_CH_CONTROL(Channel));

    value = value & (~DMA_CH_CTRL_PBL);

    value |= ((skip << DMA_CH_CTRL_DSL_SHIFT) & DMA_CH_CTRL_DSL_MASK);

    writel(value, RegBase + DMA_CH_CONTROL(Channel));

}
/*
    DMA_SYSBUS_FB
    DMA_SYSBUS_MB
    DMA_SYSBUS_AAL
    DMA_SYSBUS_EAME
    DMS_SysBus_param;
*/
/**
 * @brief Initializes the DMA bus mode register with specified flags.
 *
 * This function initializes the DMA bus mode register by applying a set of specified flags to configure
 * the DMA bus behavior. The flags are masked against `DMA_AXI_SYS_MASK` to ensure only relevant bits are
 * modified, and then written to the DMA system bus mode register.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Flags A bitmask of flags to apply to the DMA bus mode register. Only bits defined in
 *              `DMA_AXI_SYS_MASK` are considered.
 *
 * @note The `DMA_SYSBUS_MODE`, `DMA_AXI_SYS_MASK`, `readl`, and `writel` macro/function are assumed to be
 *       defined and provide the correct offsets, masks, and functionality for accessing and modifying the
 *       DMA bus mode register.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_bus_init(uint32 RegBase, uint32 Flags)
{
    uint32 value = readl(RegBase + DMA_SYSBUS_MODE);
    value |= Flags & DMA_AXI_SYS_MASK;
    writel(value, RegBase + DMA_SYSBUS_MODE);
}
/**
 * @brief Retrieves the receive state of the specified DMA channel.
 *
 * This function retrieves the current receive state of the specified DMA channel by reading the relevant
 * debug status register and extracting the state information for the given channel. The state is returned
 * as an enumeration value of type `enum dma_rx_status`.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number to retrieve the receive state for.
 *
 * @return The receive state of the specified DMA channel, represented as an enumeration value of type
 *         `enum dma_rx_status`.
 *
 * @note The function assumes that the `DMA_DEBUG_STATUS0`, `DMA_DEBUG_STATUS2`, `readl` macro/function,
 *       and `enum dma_rx_status` enumeration are defined and provide the correct offsets, functionality,
 *       and enumeration values for accessing and interpreting the DMA debug status registers. The function
 *       supports DMA channels 0 to 4, and assumes that the state information for each channel is encoded
 *       in a specific bit field within the debug status registers.
 */
enum dma_rx_status dwmac_dma_rx_state_get(uint32 RegBase, uint32 Channel)
{
    uint32 state = DMX_RX_RSVD;

    if(Channel < 3u){
        state = (readl(RegBase + DMA_DEBUG_STATUS0) >> (Channel * 8 + 8)) & 0xF;
    }else if(Channel < 5u){
        state = (readl(RegBase + DMA_DEBUG_STATUS2) >> ((Channel - 3) * 8)) & 0xF;
    }/* else is not needed */
    return (enum dma_rx_status)state;
}

/**
 * @brief Configures the transmit channel weight and enables transmit arbitration algorithm.
 *
 * This function configures the transmit channel weight for the specified DMA channel, as well as enables
 * the transmit arbitration algorithm for better transmission scheduling. The transmit channel weight
 * (TWC) determines the priority given to the channel during transmit arbitration. The transmit arbitration
 * algorithm (TAA) is also enabled to allow for more efficient transmission scheduling based on the
 * configured weights.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Channel The DMA channel number to configure the transmit channel weight for.
 * @param twc The transmit channel weight value to set.
 *
 * @note The `DMA_CH_TX_CONTROL`, `DMA_CH_TX_CTRL_TCW_MASK`, `DMA_CH_TX_CTRL_TCW_SHIFT`, `DMA_MODE`,
 *       `DMA_BUS_TAA_MASK`, `DMA_BUS_TAA_SHIFT`, `readl`, and `writel` macro/function are assumed to be
 *       defined and provide the correct offsets, masks, constants, and functionality for accessing and
 *       modifying the DMA transmit control and bus mode registers.
 *
 * @return None. This function does not return a value.
 */
void dwmac_dma_tx_chan_weight(uint32 RegBase, uint32 Channel, uint32 twc)
{
    uint32 val = readl(RegBase + DMA_CH_TX_CONTROL(Channel));
    val &= ~DMA_CH_TX_CTRL_TCW_MASK;
    val |=  (twc << DMA_CH_TX_CTRL_TCW_SHIFT) & DMA_CH_TX_CTRL_TCW_MASK;
    writel(val, RegBase + DMA_CH_TX_CONTROL(Channel));

    val = readl(RegBase + DMA_MODE);
    val &= ~DMA_BUS_TAA_MASK;
    val |=  (1 << DMA_BUS_TAA_SHIFT) & DMA_BUS_TAA_MASK;
    writel(val, RegBase + DMA_MODE);
}

/**
 * @brief Sets the buffer size for the specified DMA receive channel based on the maximum transmission unit (MTU).
 *
 * This function configures the buffer size for the specified DMA receive channel by calculating the
 * required buffer size based on the maximum transmission unit (MTU) and rounding it up to the nearest
 * multiple of 16 bytes. The calculated buffer size is then written to the receive control register of
 * the DMA channel.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param mtu The maximum transmission unit (MTU) value, which determines the maximum size of the
 *            packets that can be transmitted or received.
 * @param Channel The DMA receive channel number to set the buffer size for.
 *
 * @note The `DMA_CH_RX_CONTROL`, `DMA_CH_RX_CTRL_RBSZ_MASK`, `DMA_CH_RX_CTRL_RBSZ_SHIFT`, `ETH_ROUNDUP`, `readl`, and `writel`
 *       macro/function are assumed to be defined and provide the correct offsets, masks, constants,
 *       rounding functionality, and access methods for modifying the DMA receive control register.
 *
 * @return None. This function does not return a value.
 */
void dwmac_set_bfsize(uint32 RegBase, uint32 mtu, uint32 Channel)
{
    uint32 value = readl(RegBase + DMA_CH_RX_CONTROL(Channel));
    uint32 BuffSize = ETH_ROUNDUP(mtu,16u);
    value &= ~DMA_CH_RX_CTRL_RBSZ_MASK;
    value |= ((BuffSize << DMA_CH_RX_CTRL_RBSZ_SHIFT) & DMA_CH_RX_CTRL_RBSZ_MASK);

    writel(value, RegBase + DMA_CH_RX_CONTROL(Channel));
}
/* =====================>DMA BLOCK END<==================== */

#define MII_BUSY 0x00000001
#define MII_WRITE 0x00000002
#define MII_DATA_MASK 0xFFFF

/* GMAC4 defines */
#define MII_MAC_GOC_SHIFT       2u
#define MII_MAC_REG_ADDR_SHIFT  16u
#define MII_MAC_WRITE           (1u << MII_MAC_GOC_SHIFT)
#define MII_MAC_READ            (3u << MII_MAC_GOC_SHIFT)
#define MII_MAC_C45E            0x02u

#define MII_ADDR_OFFSET         21u
#define MII_ADDR_MASK           (0x1Fu<<MII_ADDR_OFFSET)
#define MII_REG_OFFSET          16u
#define MII_REG_MASK            (0x1Fu<<MII_REG_OFFSET)
#define MII_CLK_CSR_OFFSET      8u
#define MII_CLK_CSR_MASK        (0xfu<<8u)

/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
   IEEE 802.3ae clause 45 addressing Mode used by 10GIGE phy chips. */
#define MII_ADDR_C45 (1u<<30u)
#define MII_DEVADDR_C45_SHIFT   16u
#define MII_REGADDR_C45_MASK    0xffffu
#define CLK_CSR     0x5u


/**
 * @brief Polls the MDIO bus to check if it is busy, with a specified timeout.
 *
 * This function polls the MDIO (Management Data Input/Output) bus to determine if it is currently busy.
 * It does this by checking the MDIO busy bit in the MDIO register. If the MDIO bus is busy, it waits for
 * a short period of time before checking again, up to a specified timeout limit.
 *
 * @param RegBase The base register address of the MDIO controller.
 * @param Timeout The maximum amount of time, in units defined by the `Mcal_udelay` function, to wait for
 *                the MDIO bus to become available.
 *
 * @return Returns 0 if the MDIO bus becomes available within the specified timeout. Returns -1 if the
 *         MDIO bus remains busy after the timeout expires.
 *
 * @note The `MII_BUSY` macro/constant, `readl` macro/function, `Mcal_udelay` function, and any additional
 *       error injection or timeout handling functions (like `EthFaultInj_Eth_Mdio_Timeout`) used within
 *       this function are assumed to be defined and provide the necessary functionality.
 *
 * @warning This function uses a busy-wait polling mechanism, which can be inefficient and may consume
 *          significant CPU resources if the MDIO bus remains busy for an extended period of time.
 */
static inline sint32 poll_mdio_busy(uint32 RegBase, uint32 Timeout)
{
    // The timeout time is unchanged, and the query frequency is increased
    uint32 limit = Timeout;
    EthFaultInj_Eth_Mdio_Timeout();
    do {
        if (readl(RegBase) & MII_BUSY) {
            Mcal_udelay(1);
        } else {
            return 0;
        }

        limit--;
    } while (limit);

    return -1;
}
/**
 * @description: this function support to Access Clause 45 Phy
 * @param {uint8} PhyAddr
 * @param {uint8} Device
 * @param {uint16} PhyReg
 * @return {*}
 */
sint32 mac_mdio_read(uint32  RegBase, uint8 PhyAddr, uint8 Device, uint16 PhyReg)
{
    // Define the MII address and data registers
    uint32 mii_address = (uint32)RegBase + MAC_MDIO_ADDR;
    uint32 mii_data = (uint32)RegBase + MAC_MDIO_DATA;
    uint32 value = MII_BUSY;
    sint32 data = 0;

    // Set the PHY address and clock control register
    value |= (((uint32)PhyAddr) << MII_ADDR_OFFSET) & MII_ADDR_MASK;
    value |= (((uint32)CLK_CSR) << MII_CLK_CSR_OFFSET)& MII_CLK_CSR_MASK;
    value |= MII_MAC_READ;

    // Set the PHY register address
    if (PHY_CLAUSE_22 == (uint32)Device) {
        value |= (PhyReg  << MII_REG_OFFSET) & MII_REG_MASK;
    } else {
        value |= MII_MAC_C45E;
        value |= (uint32)((((uint32)Device)  << MII_REG_OFFSET) & MII_REG_MASK);

        data |= (uint32)((PhyReg & MII_REGADDR_C45_MASK) << MII_DEVADDR_C45_SHIFT);
    }

    // Poll the MII busy bit
    if (poll_mdio_busy(mii_address, 20000)) {
        return -1;
    }

    // Write the data to the MII data register
    writel(data, mii_data);
    writel(value, mii_address);

    // Poll the MII busy bit
    if (poll_mdio_busy(mii_address, 20000))
        return -2;

    // Read the data from the MII data register
    data = (sint32)(readl(mii_data) & MII_DATA_MASK);

    return data;
}

/**
 * @brief Writes data to a specified PHY register via the MDIO interface.
 *
 * This function writes data to a specified PHY register using the MDIO (Management Data Input/Output)
 * interface. It supports both Clause 22 and Clause 45 PHY devices and can write to any valid PHY register.
 *
 * @param RegBase The base register address of the MDIO controller.
 * @param PhyAddr The address of the PHY device to write to.
 * @param Device The PHY device type (Clause 22 or Clause 45).
 * @param PhyReg The register address within the PHY device to write to.
 * @param PhyData The data to write to the specified PHY register.
 *
 * @return Returns 0 if the write operation is successful. Returns -1 if the MDIO bus remains busy after
 *         the specified timeout period, indicating a potential communication issue.
 *
 * @note The `MAC_MDIO_ADDR`, `MAC_MDIO_DATA`, `MII_BUSY`, `MII_ADDR_OFFSET`, `MII_ADDR_MASK`,
 *       `CLK_CSR`, `MII_CLK_CSR_OFFSET`, `MII_CLK_CSR_MASK`, `MII_MAC_WRITE`, `PHY_CLAUSE_22`,
 *       `MII_REG_OFFSET`, `MII_REG_MASK`, `MII_MAC_C45E`, `MII_REGADDR_C45_MASK`, `MII_DEVADDR_C45_SHIFT`,
 *       `writel`, and `poll_mdio_busy` macro/function/constant are assumed to be defined and provide the
 *       necessary functionality for accessing and manipulating the MDIO registers and performing MDIO
 *       operations.
 *
 * @warning This function uses the `poll_mdio_busy` function to wait for the MDIO bus to become available,
 *          which employs a busy-wait polling mechanism. This can be inefficient and may consume
 *          significant CPU resources if the MDIO bus remains busy for an extended period of time.
 */
sint32 mac_mdio_write(uint32  RegBase, uint8 PhyAddr, uint8 Device, uint16 PhyReg, uint16 PhyData)
{

    uint32 mii_address = (uint32)RegBase + MAC_MDIO_ADDR;
    uint32 mii_data = (uint32)RegBase + MAC_MDIO_DATA;

    uint32 value = MII_BUSY;

    uint32 data = (uint32)(PhyData & (uint16)0xFFFF);

    value |= (PhyAddr << MII_ADDR_OFFSET) & MII_ADDR_MASK;
    value |= (CLK_CSR << MII_CLK_CSR_OFFSET) & MII_CLK_CSR_MASK;
    value |= MII_MAC_WRITE;

    if (PHY_CLAUSE_22 == Device) {
        value |= (PhyReg << MII_REG_OFFSET) & MII_REG_MASK;
    } else {
        value |= MII_MAC_C45E;
        value |= (Device << MII_REG_OFFSET) & MII_REG_MASK;

        data |= (PhyReg & MII_REGADDR_C45_MASK) << MII_DEVADDR_C45_SHIFT;
    }

    /* Wait until any existing MII operation is complete */
    if (poll_mdio_busy(mii_address, 20000)) {
        return -1;
    }

    /* Set the MII address register to write */
    writel(data,  mii_data);
    writel(value, mii_address);

    /* Wait until any existing MII operation is complete */
    return poll_mdio_busy(mii_address, 20000);
}

/**
 * Description:
 * @RegBase: points to the reg Addr
 */
boolean dwmac_access_test(uint32  RegBase)
{
    uint32 version = readl(RegBase + MAC_VERSION) & 0xFF;
    return (version == 0x52 ||  version == 0x51);
}
/**
 * @brief Updates the receive statistics based on the counters in the Ethernet controller.
 *
 * This function retrieves various receive statistics counters from the Ethernet controller and updates
 * the provided `Eth_RxStatsType` structure with the latest values. If the `Stats` parameter is `NULL`,
 * the function performs dummy reads of the counters to prevent overflow interruptions in the MMC (Management
 * Counter Module) without actually updating any statistics.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Stats A pointer to an `Eth_RxStatsType` structure where the updated receive statistics will be stored.
 *              If `NULL`, dummy reads will be performed to avoid MMC overflow interruptions.
 *
 * @note The `Eth_RxStatsType` structure and its members, such as `RxStatsDropEvents`, `RxStatsOctets`, etc.,
 *       are assumed to be defined and provide the necessary fields for storing the receive statistics.
 *       The `NULL_PTR` macro/constant, `EthFaultInj_Eth_Mmc_Counter` function (for error injection),
 *       and `readl` macro/function for reading register values are also assumed to be defined and functional.
 *
 * @note The counters read from the Ethernet controller, such as `MAC_PACKETS_RX_CONUT_DROP_PKT`,
 *       `MAC_PACKETS_RX_CONUT_ALL_BYTES`, etc., are assumed to be valid register offsets for accessing
 *       the receive statistics counters.
 */
void rx_stats_update(uint32  RegBase, Eth_RxStatsType *Stats)
{
    /*
        When the upper layer does not need statistical data packets,
        the hardware still needs to read to avoid MMC overflow interruption;
        therefore, when the upper layer does not need statistical data packets,
        NULL will be passed in here, so a dummy read here has no effect on the result
    */
    EthFaultInj_Eth_Mmc_Counter();
    if (Stats != NULL_PTR) {
        Stats->RxStatsDropEvents += readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        Stats->RxStatsOctets += readl(RegBase + MAC_PACKETS_RX_CONUT_ALL_BYTES);
        Stats->RxStatsPkts += readl(RegBase + MAC_PACKETS_RX_CONUT_ALL_PKT);
        Stats->RxStatsPkts -= readl(RegBase + MAC_PACKETS_RX_CONUT_BAD_PKT);

        Stats->RxStatsBroadcastPkts += readl(RegBase + MAC_PACKETS_RX_CONUT_BROADCAST);
        Stats->RxStatsMulticastPkts += readl(RegBase + MAC_PACKETS_RX_CONUT_MULTICAST);
        Stats->RxStatsCrcAlignErrors += readl(RegBase + MAC_PACKETS_RX_CONUT_CRC_ERR);
        Stats->RxStatsCrcAlignErrors += readl(RegBase + MAC_PACKETS_RX_CONUT_ALIGN_ERR);
        Stats->RxStatsUndersizePkts += readl(RegBase + MAC_PACKETS_RX_CONUT_UNDER_PKT);
        Stats->RxStatsOversizePkts += readl(RegBase + MAC_PACKETS_RX_CONUT_OVER_PKT);

        Stats->RxStatsFragments += readl(RegBase + MAC_PACKETS_RX_CONUT_FRAG_ERR);
        Stats->RxStatsJabbers += readl(RegBase + MAC_PACKETS_RX_CONUT_JABBER_ERR);
        /* Duplex Mode will not happen */
        Stats->RxStatsCollisions = 0;
        Stats->RxStatsPkts64Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_64);
        Stats->RxStatsPkts65to127Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_65_127);
        Stats->RxStatsPkts128to255Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_128_255);
        Stats->RxStatsPkts256to511Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_256_511);
        Stats->RxStatsPkts512to1023Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_512_1023);
        Stats->RxStatsPkts1024to1518Octets += readl(RegBase + MAC_PACKETS_RX_CONUT_1024_MAX);
        Stats->RxUnicastFrames += readl(RegBase + MAC_PACKETS_RX_CONUT_UNICAST);
    } else {
        readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_ALL_BYTES);
        readl(RegBase + MAC_PACKETS_RX_CONUT_ALL_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_BAD_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_BROADCAST);
        readl(RegBase + MAC_PACKETS_RX_CONUT_MULTICAST);
        readl(RegBase + MAC_PACKETS_RX_CONUT_CRC_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_ALIGN_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_UNDER_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_OVER_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_FRAG_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_JABBER_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_64);
        readl(RegBase + MAC_PACKETS_RX_CONUT_65_127);
        readl(RegBase + MAC_PACKETS_RX_CONUT_128_255);
        readl(RegBase + MAC_PACKETS_RX_CONUT_256_511);
        readl(RegBase + MAC_PACKETS_RX_CONUT_512_1023);
        readl(RegBase + MAC_PACKETS_RX_CONUT_1024_MAX);
        readl(RegBase + MAC_PACKETS_RX_CONUT_UNICAST);
    }
}
/**
 * @brief Updates the transmit statistics based on the counters in the Ethernet controller.
 *
 * This function retrieves various transmit statistics counters from the Ethernet controller and updates
 * the provided `Eth_TxStatsType` structure with the latest values. If the `Stats` parameter is `NULL`,
 * the function performs dummy reads of the counters to prevent overflow interruptions in the MMC (Management
 * Counter Module) without actually updating any statistics.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Stats A pointer to an `Eth_TxStatsType` structure where the updated transmit statistics will be stored.
 *              If `NULL`, dummy reads will be performed to avoid MMC overflow interruptions.
 *
 * @note The `Eth_TxStatsType` structure and its members, such as `TxNumberOfOctets`, `TxNUcastPkts`,
 *       `TxMultiCastPkts`, and `TxUniCastPkts`, are assumed to be defined and provide the necessary fields
 *       for storing the transmit statistics. The `NULL_PTR` macro/constant, `EthFaultInj_Eth_Mmc_Counter`
 *       function (for error injection), and `readl` macro/function for reading register values are also
 *       assumed to be defined and functional.
 *
 * @note The counters read from the Ethernet controller, such as `MAC_PACKETS_TX_CONUT_ALL_BYTES`,
 *       `MAC_PACKETS_TX_CONUT_BROADCAST`, `MAC_PACKETS_TX_CONUT_MULTICAST`, and
 *       `MAC_PACKETS_TX_CONUT_UNICAST`, are assumed to be valid register offsets for accessing
 *       the transmit statistics counters.
 *
 * @warning There seems to be a potential mistake in the assignment of `TxNUcastPkts` in the function body,
 *          as it is incremented by both broadcast and multicast packet counts. Typically, unicast,
 *          broadcast, and multicast packet counts are tracked separately. The intention here may have
 *          been to track non-unicast packets (broadcast + multicast) in `TxNUcastPkts`, but the naming
 *          and assignment may cause confusion. Consider renaming `TxNUcastPkts` to reflect its actual
 *          purpose (e.g., `TxNonUniCastPkts`) or adjusting the assignments accordingly.
 */
void tx_stats_update(uint32  RegBase, Eth_TxStatsType *Stats)
{
    /*
        When the upper layer does not need statistical data packets,
        the hardware still needs to read to avoid MMC overflow interruption;
        therefore, when the upper layer does not need statistical data packets,
        NULL will be passed in here, so a dummy read here has no effect on the result
    */
    EthFaultInj_Eth_Mmc_Counter();
    if (Stats != NULL_PTR) {
        Stats->TxNumberOfOctets += readl(RegBase + MAC_PACKETS_TX_CONUT_ALL_BYTES);
        Stats->TxNUcastPkts += readl(RegBase + MAC_PACKETS_TX_CONUT_BROADCAST);
        Stats->TxNUcastPkts += readl(RegBase + MAC_PACKETS_TX_CONUT_MULTICAST);
        Stats->TxUniCastPkts += readl(RegBase + MAC_PACKETS_TX_CONUT_UNICAST);
    } else {
        readl(RegBase + MAC_PACKETS_TX_CONUT_ALL_BYTES);
        readl(RegBase + MAC_PACKETS_TX_CONUT_BROADCAST);
        readl(RegBase + MAC_PACKETS_TX_CONUT_MULTICAST);
        readl(RegBase + MAC_PACKETS_TX_CONUT_UNICAST);
    }
}
/**
 * @brief Updates the Ethernet controller counters and optionally stores the results in a statistics structure.
 *
 * This function retrieves various counters from the Ethernet controller that represent various error and
 * performance metrics. If the `Stats` parameter is not `NULL`, the function will update the fields of the
 * provided `Eth_CounterType` structure with the retrieved counter values. If `Stats` is `NULL`, the
 * function will perform dummy reads of the counters to prevent MMC overflow interruptions without
 * actually storing the results.
 *
 * @param RegBase The base register address of the Ethernet controller.
 * @param Stats A pointer to an `Eth_CounterType` structure where the updated counter values will be stored.
 *              If `NULL`, dummy reads will be performed to avoid MMC overflow interruptions.
 *
 * @note The `Eth_CounterType` structure and its members, such as `DropPktBufOverrun`, `DropPktCrc`, etc.,
 *       are assumed to be defined and provide the necessary fields for storing the counter values.
 *       The `NULL_PTR` macro/constant, `EthFaultInj_Eth_Mmc_Counter` function (for error injection),
 *       and `readl` macro/function for reading register values are also assumed to be defined and functional.
 *
 * @note The counters read from the Ethernet controller, such as `MAC_PACKETS_RX_CONUT_DROP_PKT`,
 *       `MAC_PACKETS_RX_CONUT_CRC_ERR`, etc., are assumed to be valid register offsets for accessing
 *       the controller counters.
 *
 * @warning The function performs arithmetic operations on some counter values to derive certain
 *          statistics, such as subtracting the number of good transmitted packets from the total
 *          number of transmitted packets to calculate the number of errored transmitted packets.
 *          It's important to ensure that the counter values are updated atomically or that the
 *          arithmetic operations are performed in a manner that accounts for potential race conditions.
 */
void controller_counter_update(uint32  RegBase, Eth_CounterType *Stats)
{
    /*
        When the upper layer does not need statistical data packets,
        the hardware still needs to read to avoid MMC overflow interruption;
        therefore, when the upper layer does not need statistical data packets,
        NULL will be passed in here, so a dummy read here has no effect on the result
    */
    EthFaultInj_Eth_Mmc_Counter();
    if (Stats != NULL_PTR) {
        Stats->DropPktBufOverrun += readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        Stats->DropPktCrc += readl(RegBase + MAC_PACKETS_RX_CONUT_CRC_ERR);
        Stats->UndersizePkt += readl(RegBase + MAC_PACKETS_RX_CONUT_UNDER_PKT);
        Stats->OversizePkt += readl(RegBase + MAC_PACKETS_TX_CONUT_OVER_PKT);
        Stats->OversizePkt += readl(RegBase + MAC_PACKETS_RX_CONUT_OVER_PKT);
        Stats->AlgnmtErr += readl(RegBase + MAC_PACKETS_RX_CONUT_ALIGN_ERR);
        Stats->SqeTestErr = 0;
        Stats->DiscInbdPkt += readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        Stats->ErrInbdPkt += readl(RegBase + MAC_PACKETS_RX_CONUT_BAD_PKT);
        Stats->DiscOtbdPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_COLL);
        Stats->DiscOtbdPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_CARR);
        Stats->ErrOtbdPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_ALL_PKT);
        Stats->ErrOtbdPkt -= readl(RegBase + MAC_PACKETS_TX_CONUT_GOOD_PKT);
        Stats->SnglCollPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_SINGL_COLL);
        Stats->MultCollPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_MULT_COLL);
        Stats->DfrdPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_DFRD_COLL);
        Stats->LatCollPkt += readl(RegBase + MAC_PACKETS_TX_CONUT_LATE_COLL);
        Stats->HwDepCtr0 = 0;
        Stats->HwDepCtr1 = 0;
        Stats->HwDepCtr2 = 0;
        Stats->HwDepCtr3 = 0;
    } else {
        readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_CRC_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_UNDER_PKT);
        readl(RegBase + MAC_PACKETS_TX_CONUT_OVER_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_OVER_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_ALIGN_ERR);
        readl(RegBase + MAC_PACKETS_RX_CONUT_DROP_PKT);
        readl(RegBase + MAC_PACKETS_RX_CONUT_BAD_PKT);
        readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_CARR);
        readl(RegBase + MAC_PACKETS_TX_CONUT_ALL_PKT);
        readl(RegBase + MAC_PACKETS_TX_CONUT_GOOD_PKT);
        readl(RegBase + MAC_PACKETS_TX_CONUT_SINGL_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_MULT_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_DFRD_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_LATE_COLL);
    }
}

/**
 * @description:
 * @param {uint32 } RegBase
 * @param {Eth_TxErrorCounterValuesType} *count
 * @return {*}
 */
void tx_error_count_update(uint32  RegBase, Eth_TxErrorCounterValuesType *Stats)
{
    /*
        When the upper layer does not need statistical data packets,
        the hardware still needs to read to avoid MMC overflow interruption;
        therefore, when the upper layer does not need statistical data packets,
        NULL will be passed in here, so a dummy read here has no effect on the result
    */
    EthFaultInj_Eth_Mmc_Counter();
    if (Stats != NULL_PTR) {

        Stats->TxDroppedNoErrorPkts = 0;
        Stats->TxDroppedErrorPkts += readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_CARR);
        Stats->TxDeferredTrans += readl(RegBase + MAC_PACKETS_TX_CONUT_DFRD_COLL);
        Stats->TxSingleCollision += readl(RegBase + MAC_PACKETS_TX_CONUT_SINGL_COLL);
        Stats->TxMultipleCollision += readl(RegBase + MAC_PACKETS_TX_CONUT_MULT_COLL);
        Stats->TxLateCollision += readl(RegBase + MAC_PACKETS_TX_CONUT_LATE_COLL);
        Stats->TxExcessiveCollison += readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_COLL);
    } else {
        readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_CARR);
        readl(RegBase + MAC_PACKETS_TX_CONUT_DFRD_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_SINGL_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_MULT_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_LATE_COLL);
        readl(RegBase + MAC_PACKETS_TX_CONUT_DROP_PKT_COLL);
    }
}

/**
 * @brief Handles interrupts generated by the Ethernet MAC controller.
 *
 * This function is the interrupt service routine (ISR) for the Ethernet MAC controller. It reads the
 * interrupt status and enable registers to determine which interrupts are active and enabled. Based
 * on the interrupt status, it performs the necessary actions to clear the interrupts and handle any
 * associated events.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller instance being serviced.
 * @param RegBase The base register address of the Ethernet controller.
 *
 * @return An OID (Object Identifier) value, typically used for status reporting or error handling.
 *         In this context, the function does not return a meaningful OID value and always returns 0.
 *
 * @note The function assumes that the `EthFaultInj_Eth_ctrl_handle_Mmc` function is defined and used
 *       for error injection or special handling of MMC (Management Counter Module) interrupts.
 *
 * @note The function clears interrupts by reading the appropriate status registers, as required by
 *       the hardware. For example, PMT (Power Management Timer) interrupts are cleared by reading
 *       the PMT status register, and MMC interrupts are cleared by reading the MMC interrupt status
 *       registers.
 *
 * @note The function does not perform any detailed error handling or status reporting beyond clearing
 *       interrupts and calling the `Eth_update_mmc_status` function for MMC interrupts. Additional
 *       error handling or status reporting would need to be implemented by the caller or in separate
 *       functions.
 */
void mac_irq_handler(uint8 CtrlIdx,uint32  RegBase)
{

    uint32 status = readl(RegBase + MAC_INT_STATUS);
    uint32 enable = readl(RegBase + MAC_INT_EN);
    uint32 mmc_copy = status;
    /* Discard disabled bits */
    status &= enable;
    EthFaultInj_Eth_ctrl_handle_Mmc();
    /* Clear the PMT bits 5 and 6 by reading the PMT status reg */
    if (status & MAC_STATUS_PMT) {
        readl(RegBase + MAC_PMT);
    }
    if (mmc_copy & MAC_STATUS_MMC) {
        Eth_update_mmc_status(CtrlIdx);
        /* read to clr */
        if (status & MAC_STATUS_MMC_IPC)
            readl(RegBase + MAC_MMC_IPC_INTR_STA);

        if (status & MAC_STATUS_MMC_TX)
            readl(RegBase + MAC_MMC_TX_INTR_STA);

        if (status & MAC_STATUS_MMC_RX)
            readl(RegBase + MAC_MMC_RX_INTR_STA);
    }

    /* MAC tx/rx EEE LPI entry/exit interrupts */
    if (status & MAC_STATUS_LPI) {
        /* Clear LPI interrupt by reading MAC_LPI_Control_Status */
        readl(RegBase + MAC_LPI_CTRL_STATUS);
    }

    readl(RegBase + MAC_PCS_STATUS);

    if (status & MAC_INT_RGSMIIS)
        readl(RegBase + MAC_PHYIF_CONTROL_STATUS);

}

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#ifdef __cplusplus
}
#endif
